一、Data函数
该函数返回组件实例的 data 对象。Vue 会在创建新组件实例的过程中调用此函数。它应该返回一个对象,然后 Vue 会通过响应性系统将其包裹起来,并以 $data 的形式存储在组件实例中。为方便起见,该对象的任何顶级 property 也会直接通过组件实例暴露出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="js/vue3.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"> {{count}} </div> <script type="text/javascript"> const app = Vue.createApp({ data() { return { count: 4 } } }) const vm = app.mount('#app') console.log(vm.$data.count) console.log(vm.count) vm.count = 5 console.log(vm.$data.count)
vm.$data.count = 6 console.log(vm.count) </script>
</body> </html>
|
实例创建之后,可以通过 vm.$data
访问原始数据对象。组件实例也代理了 data 对象上所有的 property,因此访问 vm.a
等价于访问 vm.$data.a
。
注:以 _
或 $
开头的 property 不会被组件实例代理,因为它们可能和 Vue 内置的 property、API 方法冲突。你可以使用例如 vm.$data._property
的方式访问这些 property。
二、methods方法
我们用 methods选项向组件实例添加方法,这个methods方法是一个包含我们所需方法的对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div id="app"> <button v-on:click="add">Dianji</button> {{cnt}} </div> <script type="text/javascript"> const vm = { data() { return { cnt: 1 } }, methods: { add() { this.cnt = this.cnt + 1 } } } Vue.createApp(vm).mount('#app') </script>
|
Vue 自动为 methods 绑定 this,以便于它始终指向组件实例。这将确保方法在用作事件监听或回调时保持正确的 this指向。
在定义 methods 时应避免使用箭头函数,因为这会阻止 Vue 绑定恰当的 this 指向。
三、 computed监听
计算属性的结果会被缓存,只有当依赖的响应式 property 变化时才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。
3.1 计算属性是根据依赖关系进行缓存的计算,并且只在需要的时候进行更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="app"> <p>原数据:{{msg}}</p> <p>新数据: {{reversedMsg}}</p> </div> <script type="text/javascript"> const vm = { data() { return { msg: 'hello world!' } }, computed: { reversedMsg() { return this.msg.split('').reverse().join(''); } } } Vue.createApp(vm).mount('#app')
|
3.2 对数据进行过滤处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="app"> {{moneyStr}} </div> <script src="https://unpkg.com/vue@next"></script> <script> Vue.createApp({ data() { return { money: 100 } }, computed:{ moneyStr(){ return this.money + '¥' } } }).mount('#app') </script>
|
四、methods方法与computed计算属性的区别
虽然使用computed和methods方法两种方法实现一个功能的结果是相同的,但本质是不一样的。
计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变的时候才会重新求值,这就意味着只要message还没有发生改变,多次访问reversedMessage计算属性立即返回的是之前计算的结果,而不会再次执行计算函数。
而对于methods方法,只要发生重新渲染,methods调用总会执行该函数。
如果某个computed需要的遍历一个极大的数组和做大量的计算,可以减小性能开销,如果不希望有缓存,则用methods。
五、watch 监听器
watch能够监听数据的改变。监听之后会调用一个回调函数。
此回调函数的参数有两个:
更新后的值(新值)
更新前的值(旧值)
5.1 浅度监听
下面使用watch来监听商品数量的变化。如果商品数量小于1,就重置成上一个值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <div id="app"> <table width="100%" style="text-align: center;"> <tr> <th>商品编号</th> <th>商品名称</th> <th>商品单价</th> <th>商品数量</th> <th>合计</th> </tr> <tr> <td>1</td> <td>小米10</td> <td>{{price}}</td> <td> <button @click="subtract">-</button> {{quantity}} <button @click="add">+</button> </td> <td>{{totalPrice}}</td> </tr> </table> </div>
<script type="text/javascript"> Vue.createApp({ data() { return { price: 2999, quantity: 1 } }, computed: { totalPrice() { return this.price*this.quantity } }, methods: { add() { this.quantity++; }, subtract() { this.quantity--; } }, watch: { quantity(newVal, oldVal) { console.log(newVal, oldVal); this.quantity = newVal <= 0 ? oldVal : newVal } } }).mount('#app') </script>
|
5.2 深度监听
在上面的例子中,监听的简单的数据类型,数据改变很容易观察,但是当需要监听的数据变为对象类型的时候,上面的监听方法就失效了,因为上面的简单数据类型属于浅度监听,对应的对象类型就需要用到深度监听,只需要在上面的基础上加上deep: true就可以了。
5.2.1 错误示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <div id="app"> <table width="100%" style="text-align: center;"> <tr> <th>商品编号</th> <th>商品名称</th> <th>商品单价</th> <th>商品数量</th> <th>合计</th> </tr> <tr> <td>1</td> <td>小米10</td> <td>{{goods.price}}</td> <td> <button @click="subtract">-</button> {{goods.quantity}} <button @click="add">+</button> </td> <td>{{totalPrice}}</td> </tr> </table>
</div>
<script type="text/javascript"> Vue.createApp({ data() { return { goods: { price: 2999, quantity: 1 } } }, computed: { totalPrice() { return this.goods.price * this.goods.quantity; } }, methods: { add() { this.goods.quantity++; }, subtract() { this.goods.quantity--; } }, watch: { goods: { handler(newVal, oldVal) { console.log(newVal, oldVal); this.goods.quantity = newVal.quantity <= 0 ? oldVal.quantity : newVal.quantity; }, deep: true } } }).mount('#app') </script>
|
5.2.2 解决方案
利用计算属性将对象变成字符串后再监听。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <div id="app"> 商品名称:{{goods.name}}; 数量: <button @click="sub">-</button>{{goods.quantity}}<button @click="add">+</button> <br> 总价:{{total}} </div>
<script> Vue.createApp({ data() { return { goods: { name: '小米手机', quantity: 1 } } }, computed: { total() { return this.goods.quantity * 100; }, goodsStr() { return JSON.stringify(this.goods); } }, methods: { add() { this.goods.quantity++; }, sub() { this.goods.quantity--; } }, watch: { goodsStr(newVal, oldVal) { newGoods = JSON.parse(newVal); oldGoods = JSON.parse(oldVal); this.goods.quantity = newGoods.quantity<=0?oldGoods.quantity:newGoods.quantity;
} } }).mount('#app'); </script>
|