基础整理vue

vue笔记

模板语法

文本插值

最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):

vue
复制代码
<span>Message: {{ msg }}</span>

双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。

原始 HTML

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令

vue
复制代码
<p>Using text interpolation: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p>

在当前组件实例上,将此元素的 innerHTML 与 rawHtml 属性保持同步。

Attribute 绑定

双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令

vue
复制代码
<div v-bind:id="dynamicId"></div>

简写

因为 v-bind 非常常用,我们提供了特定的简写语法:

vue
复制代码
<div :id="dynamicId"></div>

布尔型 Attribute

布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。disabled 就是最常见的例子之一。

v-bind 在这种场景下的行为略有不同:

vue
复制代码
<button :disabled="isButtonDisabled">Button</button>

动态绑定多个值

如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:

js
复制代码
const objectOfAttrs = { id: 'container', class: 'wrapper' }

通过不带参数的 v-bind,你可以将它们绑定到单个元素上:

js
复制代码
<div v-bind="objectOfAttrs"></div>

使用 JavaScript 表达式

js
复制代码
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div :id="`list-${id}`"></div>

每个绑定仅支持单一表达式,也就是一段能够被求值的 JavaScript 代码。一个简单的判断方法是是否可以合法地写在 return 后面。

下面的例子都是无效的:

js
复制代码
<!-- 这是一个语句,而非表达式 --> {{ var a = 1 }} <!-- 条件控制也不支持,请使用三元表达式 --> {{ if (ok) { return message } }}

调用函数

可以在绑定的表达式中使用一个组件暴露的方法:

vue
复制代码
<time :title="toTitleDate(date)" :datetime="date"> {{ formatDate(date) }} </time>

指令 Directives

指令是带有 v- 前缀的特殊 attribute

v-textv-htmlv-showv-ifv-elsev-else-ifv-forv-onv-bind
v-modelv-slotv-prev-oncev-memov-cloak

v-text

vue
复制代码
<span v-text="msg"></span> <!-- 等同于 --> <span>{{msg}}</span>

v-html

v-html 的内容直接作为普通 HTML 插入—— Vue 模板语法是不会被解析的

vue
复制代码
<div v-html="<span>message</span>"></div>

v-show

基于表达式值的真假性,来改变元素的可见性。

v-show 通过设置内联样式的 display CSS 属性来工作,当元素可见时将使用初始 display 值。当条件改变时,也会触发过渡效果。

v-if

基于表达式值的真假性,来条件性地渲染元素或者模板片段。

v-if 元素被触发,元素及其所包含的指令/组件都会销毁和重构。如果初始条件是假,那么其内部的内容根本都不会被渲染。

v-else v-else-if

表示 v-ifv-if / v-else-if 链式调用的“else 块”。

vue
复制代码
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>

v-for

基于原始数据多次渲染元素或模板块。

vue
复制代码
<div v-for="(item, index) in items"></div> <div v-for="(value, key) in object"></div> <div v-for="(value, name, index) in object"></div>

v-on 事件监听器

给元素绑定事件监听器。

缩写:@

期望的绑定值类型:Function | Inline Statement | Object (不带参数)

参数:event (使用对象语法则为可选项)

常用事件修饰符
  • .stop - 调用 event.stopPropagation()。 停止传播
  • .prevent - 调用 event.preventDefault()。 阻止默认事件
  • .capture - 在捕获模式添加事件监听器。
  • .self - 只有事件从元素本身发出才触发处理函数。
  • .{keyAlias} - 只在某些按键下触发处理函数。
  • .once - 最多触发一次处理函数。
  • .left - 只在鼠标左键事件触发处理函数。
  • .right - 只在鼠标右键事件触发处理函数。
  • .middle - 只在鼠标中键事件触发处理函数。
  • .passive - 通过 { passive: true } 附加一个 DOM 事件。
键盘按键事件修饰符
  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
系统按键修饰符
  • .ctrl
  • .alt
  • .shift
  • .meta

.exact 修饰符

.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。

vue
复制代码
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 --> <button @click.ctrl="onClick">A</button> <!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 仅当没有按下任何系统按键时触发 --> <button @click.exact="onClick">A</button>

v-bind 动态属性绑定

动态的绑定一个或多个 attribute,也可以是组件的 prop。

当不带参数使用时,可以用于绑定一个包含了多个 attribute 名称-绑定值对的对象。

vue
复制代码
<!-- 绑定 attribute --> <img v-bind:src="imageSrc" /> <!-- 动态 attribute 名 --> <button v-bind:[key]="value"></button> <!-- 缩写 --> <img :src="imageSrc" /> <!-- 缩写形式的动态 attribute 名 (3.4+),扩展为 :src="src" --> <img :src /> <!-- 动态 attribute 名的缩写 --> <button :[key]="value"></button> <!-- 内联字符串拼接 --> <img :src="'/path/to/images/' + fileName" /> <!-- class 绑定 --> <div :class="{ red: isRed }"></div> <div :class="[classA, classB]"></div> <div :class="[classA, { classB: isB, classC: isC }]"></div> <!-- style 绑定 --> <div :style="{ fontSize: size + 'px' }"></div> <div :style="[styleObjectA, styleObjectB]"></div> <!-- 绑定对象形式的 attribute --> <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div> <!-- prop 绑定。“prop” 必须在子组件中已声明。 --> <MyComponent :prop="someThing" /> <!-- 传递子父组件共有的 prop --> <MyComponent v-bind="$props" /> <!-- XLink --> <svg><a :xlink:special="foo"></a></svg>

v-model 表单输入绑定

在表单输入元素或组件上创建双向绑定。

仅限:

  • <input>
  • <select>
  • <textarea>
  • components

修饰符

  • .lazy - 监听 change 事件而后更新数据
  • .number - 将输入的合法字符串转为数字
  • .trim - 移除输入内容两端空格

v-slot 插槽

用于声明具名插槽或是期望接收 props 的作用域插槽。

v-pre Vue 模板语法被保留并按原样渲染

元素内具有 v-pre,所有 Vue 模板语法都会被保留并按原样渲染。最常见的用例就是显示原始双大括号标签及内容。

v-once 仅渲染元素和组件一次

仅渲染元素和组件一次,并跳过之后的更新。元素/组件及其所有子项将被当作静态内容并跳过渲染。这可以用来优化更新时的性能。

v-memo

缓存一个模板的子树。在元素和组件上都可以使用。为了实现缓存,该指令需要传入一个固定长度的依赖值数组进行比较。如果数组里的每个值都与最后一次的渲染相同,那么整个子树的更新将被跳过。举例来说:

当组件重新渲染,如果 valueAvalueB 都保持不变,这个 <div> 及其子项的所有更新都将被跳过。实际上,甚至虚拟 DOM 的 vnode 创建也将被跳过,因为缓存的子树副本可以被重新使用。

v-cloak

用于隐藏尚未完成编译的 DOM 模板。

响应式基础

声明响应式状态

ref()

在组合式 API 中,推荐使用 ref() 函数来声明响应式状态:

js
复制代码
const count = ref(0) console.log(count) // { value: 0 } console.log(count.value) // 0 count.value++ console.log(count.value) // 1

要在组件模板中访问 ref,请从组件的 setup() 函数中声明并返回它们:

js
复制代码
import { ref } from 'vue' export default { // `setup` 是一个特殊的钩子,专门用于组合式 API。 setup() { const count = ref(0) // 将 ref 暴露给模板 return { count } } }

注意,在模板中使用 ref 时,我们需要附加 .value。为了方便起见,当在模板中使用时,ref 会自动解包

vue
复制代码
<div>{{ count }}</div>

<script setup>

setup() 函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用单文件组件 (SFC) 来避免这种情况。我们可以使用 <script setup> 来大幅度地简化代码:

vue
复制代码
<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } </script> <template> <button @click="increment"> {{ count }} </button> </template>

reactive()

reactive() 将使对象本身具有响应性

值得注意的是,reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的:

js
复制代码
const raw = {} const proxy = reactive(raw) // 代理对象和原始对象不是全等的 console.log(proxy === raw) // false

为保证访问代理的一致性,对同一个原始对象调用 reactive() 会总是返回同样的代理对象,而对一个已存在的代理对象调用 reactive() 会返回其本身:

js
复制代码
// 在同一个对象上调用 reactive() 会返回相同的代理 console.log(reactive(raw) === proxy) // true // 在一个代理上调用 reactive() 会返回它自己 console.log(reactive(proxy) === proxy) // true

reactive() 的局限性

reactive() API 有一些局限性:

  1. 有限的值类型:它只能用于对象类型 (对象、数组和如 MapSet 这样的集合类型)。它不能持有如 stringnumberboolean 这样的原始类型
  2. 不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
js
复制代码
let state = reactive({ count: 0 }) // 上面的 ({ count: 0 }) 引用将不再被追踪 // (响应性连接已丢失!) state = reactive({ count: 1 })
  1. 对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:
js
复制代码
const state = reactive({ count: 0 }) // 当解构时,count 已经与 state.count 断开连接 let { count } = state // 不会影响原始的 state count++ // 该函数接收到的是一个普通的数字 // 并且无法追踪 state.count 的变化 // 我们必须传入整个对象以保持响应性 callSomeFunction(state.count)

计算属性

使用计算属性来描述依赖响应式状态的复杂逻辑

vue
复制代码
<script setup> import { reactive, computed } from 'vue' const author = reactive({ name: 'John Doe', books: [ 'Vue 2 - Advanced Guide', 'Vue 3 - Basic Guide', 'Vue 4 - The Mystery' ] }) // 一个计算属性 ref const publishedBooksMessage = computed(() => { return author.books.length > 0 ? 'Yes' : 'No' }) </script> <template> <p>Has published books:</p> <span>{{ publishedBooksMessage }}</span> </template>

计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算

这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。

可写计算属性

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建:

js
复制代码
<script setup> import { ref, computed } from 'vue' const firstName = ref('John') const lastName = ref('Doe') const fullName = computed({ // getter get() { return firstName.value + ' ' + lastName.value }, // setter set(newValue) { // 注意:我们这里使用的是解构赋值语法 [firstName.value, lastName.value] = newValue.split(' ') } }) </script>

Class 与 Style 绑定

Vue 专门为 classstylev-bind 用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。

绑定对象

vue
复制代码
const isActive = ref(true) const hasError = ref(false) <div class="static" :class="{ active: isActive, 'text-danger': hasError }" ></div>

渲染的结果会是:

vue
复制代码
<div class="static active"></div>

绑定的对象并不一定需要写成内联字面量的形式,也可以直接绑定一个对象:

vue
复制代码
const classObject = reactive({ active: true, 'text-danger': false }) <div :class="classObject"></div>

将渲染为:

vue
复制代码
<div class="active"></div>

也可以绑定一个返回对象的计算属性。这是一个常见且很有用的技巧:

vue
复制代码
const isActive = ref(true) const error = ref(null) const classObject = computed(() => ({ active: isActive.value && !error.value, 'text-danger': error.value && error.value.type === 'fatal' })) <div :class="classObject"></div>

绑定数组

vue
复制代码
const activeClass = ref('active') const errorClass = ref('text-danger') <div :class="[activeClass, errorClass]"></div>

渲染结果

vue
复制代码
<div class="active text-danger"></div>

如果你也想在数组中有条件地渲染某个 class,你可以使用三元表达式:

text
复制代码
<div :class="[isActive ? activeClass : '', errorClass]"></div>

数组变化侦测

变更方法

Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push() 在数组末尾添加元素
  • pop() 删除数组末尾元素
  • shift() 删除数组第一个元素
  • unshift()在数组首位添加元素
  • splice() 向/从数组中添加/删除项目,然后返回被删除的项目
  • sort() 排序
  • reverse() 用于颠倒数组中元素的顺序

替换一个数组

filter()concat()slice(),这些都不会更改原数组,而总是返回一个新数组

当遇到的是非变更方法时,我们需要将旧的数组替换为新的:

js
复制代码
// `items` 是一个数组的 ref items.value = items.value.filter((item) => item.message.match(/Foo/))

展示过滤或排序后的结果

我们希望显示数组经过过滤或排序后的内容,而不实际变更或重置原始数据。在这种情况下,你可以创建返回已过滤或已排序数组的计算属性。

vue
复制代码
<template> <view class="index"> <text>{{ msg }}</text> <li v-for="n in evenNumbers">{{ n }}</li> <ul v-for="numbers in sets"> <li v-for="n in even(numbers)">{{ n }}</li> </ul> </view> </template> <script setup lang="ts"> import {ref,computed} from 'vue' import './index.scss' const msg = ref('Hello world') const sets = ref([ [1, 2, 3, 4, 5], [6, 7, 8, 9, 10] ]) function even(numbers) { return numbers.filter((number) => number % 2 === 0) } const numbers = ref([1, 2, 3, 4, 5]) const evenNumbers = computed(() => { return numbers.value.filter((n) => n % 2 === 0) }) </script>

生命周期钩子

转存失败,请重新上传图片

侦听器

在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:

vue
复制代码
<script setup> import {ref, watch} from 'vue const num = ref(0) watch(num, (newValue, oldValue) => { console.log('num 从${oldValue}变为了${newValue}') }) const incrementNum = () => num.value++ </script> <template> <!--修政购应式数据会触发侦听器--> <button @click="incrementNum">点击修改num</button> </template>

侦听数据源类型

watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

js
复制代码
const x = ref(0) const y = ref(0) // 单个 ref watch(x, (newX) => { console.log(`x is ${newX}`) }) // getter 函数 watch( () => x.value + y.value, (sum) => { console.log(`sum of x + y is: ${sum}`) } ) // 多个来源组成的数组 watch([x, () => y.value], ([newX, newY]) => { console.log(`x is ${newX} and y is ${newY}`) })

注意,你不能直接侦听响应式对象的属性值,例如:

js
复制代码
const obj = reactive({ count: 0 }) // 错误,因为 watch() 得到的参数是一个 number watch(obj.count, (count) => { console.log(`count is: ${count}`) })

这里需要用一个返回该属性的 getter 函数:

js
复制代码
// 提供一个 getter 函数 watch( () => obj.count, (count) => { console.log(`count is: ${count}`) } )

深层侦听器

直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:

js
复制代码
const obj = reactive({ count: 0 }) watch(obj, (newValue, oldValue) => { // 在嵌套的属性变更时触发 // 注意:`newValue` 此处和 `oldValue` 是相等的 // 因为它们是同一个对象! }) obj.count++

相比之下,一个返回响应式对象的 getter 函数,只有在返回不同的对象时,才会触发回调:

js
复制代码
watch( () => state.someObject, () => { // 仅当 state.someObject 被替换时触发 } )

你也可以给上面这个例子显式地加上 deep 选项,强制转成深层侦听器:

js
复制代码
watch( () => state.someObject, () => { // 仅当 state.someObject 被替换时触发 } )

即时回调的侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。

我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行:

js
复制代码
watch( source, (newValue, oldValue) => { // 立即执行,且当 `source` 改变时再次执行 }, { immediate: true } )

一次性侦听器

每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项。

js
复制代码
watch( source, (newValue, oldValue) => { // 当 `source` 变化时,仅触发一次 }, { once: true } )

watchEffect()

模板引用 (获得DOM操作)

虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。要实现这一点,我们可以使用特殊的 ref attribute:

js
复制代码
<script setup> import { ref, onMounted } from 'vue' // 声明一个 ref 来存放该元素的引用 // 必须和模板里的 ref 同名 const input = ref(null) onMounted(() => { input.value.focus() //使得input获取焦点 }) </script> <template> <input ref="input" /> </template>

组件

组件基础

props声明

一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props

js
复制代码
// 非 <script setup> export default { props: { title: String, likes: Number } }
js
复制代码
// 使用 <script setup> defineProps 属性只读 Props 属性可读写 defineProps({ title: String, likes: Number })
text
复制代码
export default { props: { title: { type:String, default:"abc" //适用基本数据类型 }, likes: { type:Array, default{ return ["abc"] //数组 对象 函数 必须是大括号包裹 return 出去 } } } }

props传递

任何类型的值都可以作为 props 的值被传递。

text
复制代码
<!-- 根据一个变量的值动态传入 --> <BlogPost :title="post.title" />

props 父组件传值子组件

子组件通过 props 声明传值属性的名称和类型以及默认值,在父组件页面通过v-bin的形式去绑定属性的关联关系即 :属性=变量值

父组件

vue
复制代码
<template> <BlogPost :title="title"></BlogPost> </template> <script> import BlogPost from './BlogPost.vue' export default { components: { BlogPost }, data() { return { "title": 'My journey with Vue' } } } </script>

子组件

vue
复制代码
<template> <h4>{{ title }}</h4> </template> <script> export default { props: ['title'] } </script>

$emit 子组件传值父组件

通过$emit("属性名称",变量值)的形式向父组件传值,父组件通过在子组件属性上添加事件监听器的方式( v-on:属性名称="函数名称")通过函数参数来接受数据

子组件

vue
复制代码
<template> <p>{{ title}}</p> <button @click="toParentHandler">向父组件传值</button> </template> <script> export default { props:["title"], data(){ return{ msg: 'aaaa' } }, methods:{ toParentHandler(){ this.$emit("msg",this.msg) } } } </script>

父组件

vue
复制代码
<template> <BlogPost :title="title" @msg="getDataHandler"></BlogPost> <p>{{msg}}</p> </template> <script> import BlogPost from './BlogPost.vue' export default { components: { BlogPost }, data() { return { title: 'My journey with Vue', msg:'' } }, methods:{ getDataHandler(data){ this.msg=data } } } </script>

子组件传值父组件 通过自定义函数传递

子组件

vue
复制代码
<template> <h4>{{ title }}</h4> <button @click="toParentHandler">函数传值传值于父组件</button> </template> <script> export default { props: ['title',"toParentHandler"], data(){ return{ msg:'abc' } },methods:{ toParentHandler(){ this.toParentHandler(this.msg) } } }

父组件

vue
复制代码
<template> <BlogPost :title="title" :toParentHandler="getParentDataHandler"></BlogPost> <p>{{ msg}}</p> </template> <script> import BlogPost from './BlogPost.vue' export default { components: { BlogPost }, data() { return { "title": 'My journey with Vue', msg:'' } },methods:{ getParentDataHandler(data){ this.msg=data } } } </script>

组件注册

全局注册 局部注册 异步组件defineAsyncComponent()

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP