个人有个习惯,就是隔一段时间有空的话就会重新看看技术栈的官方文档,每次重新看都会有新的意外的收获,就像在不同年龄的时候去看同一本书,总是伴随着不一样的体验,这感觉不错(😁)
本文主要记录一下,自己之前对于vue没注意到的一些语法或者知识点,所以内容比较散,所看文档 为vue3中文文档 :介绍 | Vue.js
目录
正文开始~
1、模板语法->动态参数
可以在指令参数中使用 JavaScript 表达式,方法是用方括号括起来:
<a v-bind:[attributeName]="url"> ... </a>
这里的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例: 组件实例有一个 data property attributeName
,其值为 "href"
,那么这个绑定将等价于 v-bind:href
。
同样地,也可以使用动态参数为一个动态的事件名绑定处理函数:
<a v-on:[eventName]="doSomething"> ... </a>
当 eventName
的值为 "focus"
时,v-on:[eventName]
将等价于 v-on:focus
2、模板语法->缩写
<!-- 完整语法 -->
<a v-bind:href="url"> ... </a>
<!-- 缩写 -->
<a :href="url"> ... </a>
<!-- 动态参数的缩写 -->
<a :[key]="url"> ... </a>
<!-- 完整语法 -->
<a v-on:click="doSomething"> ... </a>
<!-- 缩写 -->
<a @click="doSomething"> ... </a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
注意事项:
a、对动态参数值约定
动态参数预期会求出一个字符串,异常情况下值为 null
。这个特殊的 null
值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
b、对动态参数表达式约定
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML attribute 名里是无效的。
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value"> ... </a>
变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂表达式。
在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名键名,因为浏览器会把 attribute 名全部强制转为小写
<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
3、Data Property
实例 property 仅在实例首次创建时被添加,所以你需要确保它们都在 data
函数返回的对象中。必要时,要对尚未提供所需值的 property 使用 null
、undefined
或其他占位的值
Vue 使用 $
前缀通过组件实例暴露自己的内置 API。它还为内部 property 保留 _
前缀。你应该避免使用这两个字符开头的的顶级 data
property 名称。
4、方法
Vue 自动为 methods
绑定 this
,以便于它始终指向组件实例。这将确保方法在用作事件监听或回调时保持正确的 this
指向。在定义 methods
时应避免使用箭头函数,因为这会阻止 Vue 绑定恰当的 this
指向。
可以直接从模板中调用方法,一般建议用计算属性代替在模板中直接使用方法,但当计算数据不能用时,在模板中直接调用方法也未尝不可
<span :title="toTitleDate(date)">
{{ formatDate(date) }}
</span>
5、防抖和节流
Vue 没有内置支持防抖和节流,但可以使用 Lodash 等库来实现。
如果某个组件仅使用一次,可以在 methods
中直接应用防抖:
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
<script>
Vue.createApp({
methods: {
// 用 Lodash 的防抖函数
click: _.debounce(function() {
// ... 响应点击 ...
}, 500)
}
}).mount('#app')
</script>
但是,这种方法对于可复用组件有潜在的问题,因为它们都共享相同的防抖函数。为了使组件实例彼此独立,可以在生命周期钩子的 created
里添加该防抖函数:
app.component('save-button', {
created() {
// 用 Lodash 的防抖函数
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// 移除组件时,取消定时器
this.debouncedClick.cancel()
},
methods: {
click() {
// ... 响应点击 ...
}
},
template: `
<button @click="debouncedClick">
Save
</button>
`
})
6、计算属性(computed)
对于任何包含响应式数据的复杂逻辑,都建议使用计算属性
计算属性默认只有 getter,不过在需要时也可以提供一个 setter:
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
现在再运行 vm.fullName = 'John Doe'
时,setter 会被调用,vm.firstName
和 vm.lastName
也会相应地被更新。
7、侦听器(watch)
Vue 通过 watch
选项提供了一个更通用的方法来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
8、绑定Class
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute,所以我们可以用 v-bind
处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
绑定class的对象语法
//:class 指令可以与普通的 class attribute 共存
div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
我们也可以在这里绑定一个返回对象的计算属性,这是一个常用且强大的模式:
<div :class="classObject"></div>
data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject() {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
绑定class的数组语法
<div :class="[activeClass, errorClass]"></div>
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}
//渲染结果:
<div class="active text-danger"></div>
如果想根据条件切换列表中的 class,可以使用三元表达式:
<div :class="[isActive ? activeClass : '', errorClass]"></div>
不过,当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
<div :class="[{ active: isActive }, errorClass]"></div>
9、绑定内联样式Style
自动添加前缀
在 :style
中使用需要一个 vendor prefix (浏览器引擎前缀) 的 CSS property 时,Vue 将自动侦测并添加相应的前缀。Vue 是通过运行时检测来确定哪些样式的 property 是被当前浏览器支持的。如果浏览器不支持某个 property,Vue 会进行多次测试以找到支持它的前缀。
多重值
可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex
。
10、列表渲染
数组:
<div v-for="item in items">{{ item.message }}</div>
//可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法
<div v-for="item of items"></div>
在 v-for
里使用对象
//第一个参数是键值 第二个参数是键名 第三个是索引
<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>
在遍历对象时,会按 Object.keys()
的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一 key
attribute,但不要使用对象或数组之类的非基本类型值作为 v-for
的 key。请用字符串或数值类型的值。
数组检测更新
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(item => item.message.match(/Foo/))
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
在 v-for
里使用值的范围
<div id="range" class="demo">
<span v-for="n in 10" :key="n">{{ n }} </span>
</div
11、多事件处理器
事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
Submit
</button>
12、事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form @submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
13、按键修饰符
按键别名
Vue 为最常用的键提供了别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />
14、系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
.exact
修饰符
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
鼠标按钮修饰符
.left
.right
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
15、Provide / Inject
在 setup()
中使用 provide
/inject时,我们首先从 vue
显式导入
import { provide,inject } from 'vue'
provide
函数允许你通过两个参数定义 property:
- name (
<String>
类型) - value
setup() {
provide('location', 'North Pole')
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
inject
函数有两个参数:
- 要 inject 的 property 的 name
- 默认值 (可选)
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
添加响应性
为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 或 reactive。
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
provide('location', location)
provide('geolocation', geolocation)
}
修改响应式 property
当使用响应式 provide / inject 值时,建议尽可能将对响应式 property 的所有修改限制在定义 provide 的组件内部。
有时我们需要在注入数据的组件内部更新 inject 的数据。在这种情况下,我们建议 provide 一个方法来负责改变响应式 property。同时要确保通过 provide
传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly
。
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, readonly, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', readonly(location))
provide('geolocation', readonly(geolocation))
provide('updateLocation', updateLocation)
}
}
</script>
16、过渡与动画
JavaScript 钩子
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
:css="false"
>
<!-- ... -->
</transition>
ps:学习成长路上的简单记录,如有不恰当之处,欢迎交流!