<!-- 在线的Vue2开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
Vue的数据代理
做数据代理的原因,往往就是为了更方便的使用而已,如:vm._data.name变成更简便的this.name 。 这里的this就是vm,还有就是因为做了数据代理,不用写 _data,所以vm._data.name等价于 this.name 。
<body>
<div id="root">
<span>{{name}}</span>
<hr>
<button @click="modifyname">修改用户名</button>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
name: "孙悟空",
},
methods: {
modifyname() {
//数据代理使使用变得更方便
// vm._data.name = "猪八戒";
this.name = "猪八戒";
console.log(this); //Vue {_uid: 0, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}
console.log(vm); //Vue {_uid: 0, _isVue: true, __v_skip: true, _scope: EffectScope, $options: {…}, …}
console.log(vm == this); // true
console.log(vm._data == this._data); // true
console.log(vm._data.name == vm.name); // true
console.log(vm._data.name == this.name); // true
},
}
})
</script>
</body>
Vue的响应式
经典错误写法 1:
直接用赋值的方法,给Vue追加新的属性,如下面代码中的:this.age = 500。但这不是响应性的,这样写控制台有反应,但页面没反应。
<body>
<div id="root">
<button @click="modifyname">修改用户名</button>
<span>姓名是:{{name}}</span>
<hr>
<button @click="addage">临时添加年龄</button>
<span>年龄是:{{age}}</span>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
name: "孙悟空",
},
methods: {
addage: function () {
//经典错误写法1,不是响应性的,这样写控制台有反应,但页面没反应。
this.age = 500;
},
modifyname() {
//数据代理使使用变得更方便
// vm._data.name = "猪八戒";
this.name = "猪八戒";
},
}
})
</script>
</body>
原因:
- 对象中后追加的属性,Vue默认不做响应式处理。
-
如需给后添加的属性做响应式,请使用如下API:
-
Vue.set(target,propertyName/index,value) 或
-
vm.$set(target,propertyName/index,value)
-
经典错误写法 2:
为了避免直接给Vue追加新的属性,采用上述的Vue.set()写法,但出现了以下报错:
vue.js:5108 [Vue warn]: Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.
<body>
<div id="root">
<button @click="modifyname">修改用户名</button>
<span>姓名是:{{name}}</span>
<hr>
<button @click="addage">临时添加年龄</button>
<span>年龄是:{{age}}</span>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
name: "孙悟空",
},
methods: {
addage: function () {
//经典错误写法1,不是响应性的,这样写控制台有反应,但页面没反应。
// this.age = 500;
//经典错误写法2
Vue.set(vm._data, 'age', 500);
},
modifyname() {
//数据代理使使用变得更方便
// vm._data.name = "猪八戒";
this.name = "猪八戒";
},
}
})
</script>
</body>
原因:
Vue.set() 和 vm.$set() 不能直接给vm 或 vm的根数据对象(vm._data) 添加属性!!!
解决方法如下,给数据--age添加一个层级。
<body>
<div id="root">
<button @click="addage">临时添加年龄</button>
<span>年龄是:{{person.age}}</span>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
person: {
name: "孙悟空",
hobby: ['抽烟', '喝酒', '烫头'],
}
},
methods: {
addage: function () {
//经典错误写法,不是响应性的,这样写控制台有反应,但页面没反应。
// this.person.age = 500;
//正确写法1
Vue.set(vm._data.person, 'age', 500);
//正确写法2
vm.$set(vm._data.person, 'age', 500);
this.$set(this._data.person, 'age', 500);
},
}
})
</script>
</body>
经典错误写法 3:
直接找到数组里的某个元素进行赋值修改,例如:
vm.items[index] = newValue。你确实改了,但是
Vue 不认:
<body>
<div id="root">
<h3>爱好:</h3>
<button @click="modifyHobby">新增爱好</button>
<ul>
<li v-for="(h,index) in person.hobby" :key="index">
{{h}}
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
person: {
name: "孙悟空",
hobby: ['抽烟', '喝酒', '烫头'],
}
},
methods: {
modifyHobby: function () {
//经典错误写法3,用索引直接设置一个数组项,页面检测不到变化。
this.person.hobby[0] = "赌博";
// 正确写法1----Vue.set
Vue.set(vm.person.hobby, 0, "赌博");
// 正确写法2----Array.prototype.splice
vm.person.hobby.splice(0, 1, "赌博");
},
}
})
</script>
</body>
在Vue修改数组中的某个元素一定要用如下方法:
- 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
- Vue.set() 或 vm.$set()
延申--关于Vue数组里的元素为对象
- (this.persons[0]为对象,name 为对象里的属性)。对象里的属性,是有为它服务的setter跟getter的,因此可以使用 this.persons[0].name = '马老师'; 的方式修改页面。
- 但是却没有为数组里的某个元素/对象 persons[0] 服务的setter跟getter的,因此不可以使用 this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} ; 来修改页面。
-
在Vue修改数组中的某个元素一定要用如下方法:
-
使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
-
Vue.set() 或 vm.$set()
-
<body>
<!-- 准备好一个容器-->
<div id="root">
<h2>人员列表</h2>
<button @click="updateMei">更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) of persons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '马冬梅', age: 30, sex: '女' },
{ id: '002', name: '周冬雨', age: 31, sex: '女' },
{ id: '003', name: '周杰伦', age: 18, sex: '男' },
{ id: '004', name: '温兆伦', age: 19, sex: '男' }
]
},
methods: {
updateMei() {
// this.persons[0].name = '马老师' //奏效
// this.persons[0].age = 50 //奏效
// this.persons[0].sex = '男' //奏效
// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
// this.persons.splice(0, 1, { id: '001', name: '马老师', age: 50, sex: '男' }); //奏效
Vue.set(this.persons,0,{ id: '001', name: '马老师', age: 50, sex: '男' }) //奏效
}
}
})
</script>
</body>
从别人的文章里看到的彩蛋:
如果你想要属性是响应式的,就一定要写在data对象里。因为VUE只对data里的属性做reactive化处理。或者使用Vue.set(vm.someObject, 'b', 2)动态添加。
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的
参考链接: