在 vue 中,建立實體後才加入的屬性因為沒有被給予 getter 及 setter ,所以不會被響應系統察覺,但使用 set 方法加入的屬性則會被賦予 getter 及 setter ,因此使用 set 加入的屬性都可以被響應在頁面上。
* vue 無法在建立實體後增加屬性
只有一開始定義在選項物件上的屬性才會被 vue 當作響應物件,其他未在選項物件上的屬性都無法用直接加入的方式使其成為響應物件。
栗子一:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
a: {{a}}, b: {{b}}
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
a: 1
},
created() {
this.b = 1;
}
}
);
</script>
</body>
</html>
這裡我們在實體上設了兩個屬性: a 、 b ,其中 a 是用選項物件上的 data 設定,而 b是在 created 鉤子函數裡直接在實體( this )中新增
結果如下:
在控制器中我改變了a的值,頁面上的a也相應變成了2,但是b卻沒沒改變。 所以:只有 a 的 get 及 set 方法
為了使新加入的屬性擁有 getter 及 setter ,我們要使用 set 方法。
set 方法
set 方法可以在響應物件上加上屬性,使得此屬性也是響應的,但 set 有一個限制: 對象不能是 Vue 實體或是 Vue 實體的 root 資料物件,這項限制代表我們無法將上例的 b變為響應,因為 Vue 實體的 root 資料物件,但我們能新增資料物件中的屬性。
栗子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
woman: {{user.name}},age: {{user.age}}
</div>
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
user: {
name: 'susan', // reactive
},
},
created() {
this.user.age = 18; // not reactive
}
}
);
</script>
</body>
</html>
就如上面所述的結果,並且在物件裡因為沒有實體中其他的屬性,我們可以更清楚的看出只有name 有 get 及 set 方法,而 age沒有。
這個問題可以透過 set 來處理,其定義如下:
Vue.set( target, key, value )
- target : 目標物件或是目標陣列。
- key : 目標屬性或是陣列元素位置。
- value : 欲賦予的資料值。
現在我們使用 set 將 age加入響應系統中:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
woman: {{user.name}},age: {{user.age}}
</div>
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
user: {
name: 'susan', // reactive
},
},
created() {
this.$set(this.user, 'age', '23');
}
}
);
</script>
</body>
</html>
可以在console中查看:這次 age可以響應在頁面上了。
* 物件新增多個屬性
有時你可能不會只想要新增一個屬性,這時可以有兩種方式:
- 叫用多次 set 設定每個屬性。
- 使用 Object.assign() 或是 _.extend() 這類合併多個物件的方法
this.user = Object.assign({}, this.user, {age: 17, account: 'susan123'});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue </title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
woman: {{user.name}}, age: {{user.age}}
</div>
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
user: {
name: 'susan', // reactive
},
},
created() {
this.user = Object.assign({}, this.user, {age: 17, account: 'susan123'});
}
}
);
</script>
</body>
</html>
結果為:
我們創了一個全新的空物件,並把 user及想要加入的屬性合併進去,接著在設定給 user,這樣一來就可以觸發 user的 setter 使其重新設置所有的屬性為響應的。
栗子一:添加數據
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue </title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in arr">{{item.weather}}</li>
</ul>
<button type="button" @click="Click1()">添加雨天</button>
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
arr: [
{
weather:'晴天'
},
{
weather:'陰天'
},
{
weather:'雷雨天'
}
],
},
methods:{
Click1:function(){
this.arr.push({weather:"雨天"});//为data中的items动态新增一条数据
}
}
}
);
</script>
</body>
</html>
結果為:點擊雨天就增加雨天
栗子二:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue </title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-for="item in arr" :key="item.age">
{{item.name}}
</p>
<button class="btn" @click="Click1()">susan1會換成susan4</button><br />
<button class="btn" @click="Click2()">新增susan5</button>
</div>
<script>
var vm = new Vue(
{
el: "#app",
data: {
arr: [
{ name: "susan1", age: 15 },
{ name: "susan2", age: 16 },
{ name: "susan3", age: 17 }
],
},
methods: {
Click1: function () {
Vue.set(this.arr, 0, { name: "susan4", age: 18 })
},
Click2: function () {
var arrLen = this.arr.length;
Vue.set(this.arr, arrLen, { name: "susan5", id: arrLen });
}
}
}
);
</script>
</body>
</html>
結果為:
點擊前:
點擊后:
點擊susan1會換成susan4的button,susan1會變成susan4
點擊新增susan5則會相應增加一個Susan5
說明:set可以修改數據也可以增加數據。