组件的 data
选项是一个函数。Vue 在创建新组件实例的过程中会自动调用此函数。
data
选项通常返回一个对象,然后 Vue 会通过响应性系统将其包裹起来,并以 $data
的形式存储在组件实例中。
为方便起见,作为语法糖,该对象的任何顶级属性也可以通过组件实例直接调用:
const app = Vue.createApp({ data() { return { count: 4 } } }) const vm = app.mount('#app') console.log(vm.$data.count) // => 4 console.log(vm.count) // => 4 // 修改 vm.count 的值也会更新 $data.count vm.count = 5 console.log(vm.$data.count) // => 5 // 反之亦然 vm.$data.count = 6 console.log(vm.count) // => 6
这些实例属性仅在实例首次创建时被自动添加,所以你需要确保它们都在 data
函数返回的对象中。必要时,要对尚未提供所需值的属性使用 null
、undefined
或其他占位的值。
在Vue实例被初始化后,再往data中手动添加新属性虽然是可以操作的,但该新属性不具备响应式功能,只是个傻瓜属性。
Vue 使用
$
前缀通过组件实例暴露自己的内置 API。Vue还为内部属性保留_
前缀。也就是说,你给自家的变量起名字一定不能用这两个符号开头。
Vue通过methods
选项为组件实例添加方法,选项对应的值是一个“字典”对象,对象中的每个元素是你自定义的一系列方法:
const app = Vue.createApp({ data() { return { count: 4 } }, methods: { increment() { // `this` 指向该组件实例 this.count++ } } }) const vm = app.mount('#app') console.log(vm.count) // => 4 vm.increment() console.log(vm.count) // => 5
Vue 会自动为 methods
绑定 this
,以便于它始终指向组件实例。这将确保方法在用作事件监听或回调时保持正确的 this
指向。所以在定义 methods
时应避免使用箭头函数,因为这会阻止 Vue 绑定恰当的 this
指向。
methods
和组件实例的其它所有属性一样可以在组件的模板中被访问。在模板中,它们通常被当做事件监听使用,比如:
<button @click="increment">Up vote</button>
在上面的例子中,点击 <button>
时,会调用 increment
方法。
也可以直接在模板支持 JavaScript 表达式的任何地方调用方法:
<span :title="toTitleDate(date)"> {{ formatDate(date) }} </span> // 思考一下,如果是这样,会不会调用toTitleDate方法呢? // <span title="toTitleDate(date)">
科普
案例:浏览器的scroll(滚动条滚动)、keypress(按动按键)、mousemove(鼠标移动)、窗口拖动等等事件在触发时,会不断的调用绑定在事件上的回调函数,如果回调函数比较复杂就会导致响应跟不上触发,有可能造成页面的卡顿,极大地浪费资源,降低前端的性能。
对此有两种解决方案:防抖(debounce ) 和 节流(throttling );
防抖:对在短时间内多次触发事件的回调函数,只执行最后一次,或者只在最开始时执行。
节流:类似防抖,不过节流是在一段时间之内只允许回调函数执行一次。
总之,防抖是整个过程只允许最开始或结尾执行一次。节流是在整个过程中每隔一定时间执行一次。根据不同场景选择合适的用法。对于有停顿的高频触发事件建议选择防抖,然而对于高频触发并且连续的事件,选择节流。
参考: https://segmentfault.com/a/1190000018428170?utm_source=tag-newest
无防抖功能的例子:
<html> <script src="https://unpkg.com/vue@next"></script> <body> <div id="test"> <span @drag="print">选择这段文本,拖动它!观察console!</span> </div> <script> const app = Vue.createApp({ methods: { print(){ console.log('drag') } }, }) app.mount('#test') </script> </body> </html>
Vue 没有内置支持防抖和节流功能,但可以使用 Lodash 等库来实现。
如果某个组件仅使用一次,可以在 methods
中直接应用防抖:
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script> <script> Vue.createApp({ methods: { // 用 Lodash 的防抖函数 // lodash会自动注册为下划线变量 click: _.debounce(function() { // ... 响应点击 ... }, 500) } }).mount('#app') </script>
使用lodash为上面的例子添加防抖功能:
<html> <script src="https://unpkg.com/vue@next"></script> <script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script> <body> <div id="test"> <span @drag="print">选择这段文本,拖动它!观察console!</span> </div> <script> const app = Vue.createApp({ methods: { print:_.debounce(function(){ console.log('drag') },500) }, }) app.mount('#test') </script> </body> </html>
但是,当上面的方法应用于可复用组件时,却存在潜在的问题,因为它们都共享相同的防抖函数。
为了使组件实例彼此独立,可以在组件的生命周期钩子的 created
函数里添加该防抖函数,最后在unmounted
钩子函数里移除防抖函数:
app.component('save-button', { created() { // 用 Lodash 的防抖函数 this.debouncedClick = _.debounce(this.click, 500) }, unmounted() { // 移除组件时,取消定时器 this.debouncedClick.cancel() }, methods: { click() { // ... 响应点击 ... } }, template: ` <button @click="debouncedClick"> Save </button> ` })