Vue 建構函式、生命週期與資料雙向繫結
Vue2 建構函式、生命週期與資料雙向繫結
Vue是一個響應式的、漸進式的JavaScript框架,它在設計上採用MVVM模式,將檢視與資料兩部分分離。下面就是一個簡單的Vue例項:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script >
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
var app=new Vue({
el:"#app",
data:{
message:"Hello Vue!"
}
})
</script>
</body>
</html>
可以開啟瀏覽器的控制檯,改變app.message的值,可以看到頁面上的檢視顯示部分也會相應的更新。
(1)通過Vue建構函式函式來建立Vue例項
var app = new Vue({
})
變數app就是指這個Vue例項。
在Vue例項中,el選項是必須的,el用於指定一個頁面上已存在的DOM元素來掛載Vue例項,例如:
<div id="app"></div>
<script>
var app=new Vue({
el:"#app",
})
</script>
之後可以通過app.$el來訪問這個被掛載的元素。
console.log(app.$el)
//<div id="app"></div>
(2)例項的生命週期鉤子函式
每個Vue例項建立時,都會經歷一系列初始化的過程,同時也會呼叫相應的生命週期鉤子函式。比較常用的有:
1.created
例項建立完成後呼叫,在這個階段完成了資料的觀測等,但尚未掛載,$el還不可用。
2.mounted
el掛載到例項上之後呼叫。
3.beforeDestroyed
例項銷燬之前呼叫。主要解綁一些使用addEventListener監聽的事件等。
這些生命週期鉤子函式與data類似,也可以寫入Vue例項內,並且生命週期鉤子函式內的this指向的是呼叫它的Vue例項。
var app=new Vue({
el:"#app",
data:{
a:"Hello Vue!"
},
created:function(){
console.log(this.a);
//Hello Vue!
},
mounted:function () {
console.log(this.$el);
//<div id="app">
// Hello Vue!
// </div>
}
});
不要在選項屬性或回撥上使用箭頭函式,比如 created: () => console.log(this.a)。
ES6中提到:在箭頭函式中沒有自己的this物件,導致內部的this就是外層程式碼的this。
所以,個人理解在選項屬性或回撥上使用箭頭函式,此時的this指向的是全域性屬性:
var app=new Vue({
el:"#app",
data:{
a:"Hello Vue!"
},
created:()=>{
console.log(this.a);
//undefined
},
mounted:()=> {
console.log(this.$el);
//undefined
}
});
var a=123;
var $el=456;
var app=new Vue({
el:"#app",
data:{
a:"Hello Vue!"
},
created:()=>{
console.log(this.a);
//123
},
mounted:()=> {
console.log(this.$el);
//456
}
});
(3)資料的雙向繫結
Vue實現了資料的雙向繫結,通過Vue內的data選項,聲名需要繫結的資料。
var app=new Vue({
el:"#app",
data:{
a:"Hello Vue!"
}
});
Vue本身也代理了data物件裡面的所有屬性,所以對於以上程式碼,data中的a屬性,可以通過app.a進行訪問:
console.log(app.a)
//Hello Vue!
除了顯式的聲名資料,也可以指向一個已有的變數,並且它們之間預設建立了雙向繫結,當修改其中一個時,另一個也會變化。
let test={
a:"Hello Vue!"
};
var app=new Vue({
el:"#app",
data:test,
});
console.log(app.a);
//Hello Vue!
app.a="Hello World!";
console.log(test.a);
//Hello World!
test.a="Hello simple!";
console.log(app.a);
//Hello simple!
需要注意只有當例項被建立時存在的屬性才是響應式的:
let test = {
a: "Hello Vue!"
};
var app = new Vue({
el: "#app",
data: test,
});
test.b = 1;
console.log(test.b);//1
console.log(app.b);//undefined
上面程式碼中,在Vue例項被建立時,物件中只有屬性a,之後在Vue例項建立完成後,給obj新增屬性b,這時屬性b不是響應式的。
1.雙大括號的文字插值
<div id="app">
{{ message }}
</div>
<script>
var app=new Vue({
el:"#app",
data:{
message:"Hello Vue!"
}
})
</script>
雙大括號會被替換成Vue例項上的data物件上的message屬性的值。無論何時,只要繫結的資料物件上的message屬性的值發生了改變,插值處的內容都會被更新。
比如下面的例子,實時顯示當前時間,每秒更新:
<div id="app">
{{ a }}
</div>
<script>
var app = new Vue({
el: "#app",
data: {
a: new Date()
},
mounted: function () {
var _this = this;
this.timer = setInterval(function () {
_this.a = new Date();
}, 1000);
},
beforeDestroy: function () {
if (this.timer) {
clearInterval(this.timer);
}
}
});
</script>
setTimeout()與setInterval()呼叫的程式碼執行在與所在函式完全分離的執行環境上。也就是說,setTimeout()與setInterval()程式碼中包含的 this 關鍵字會指向 window (或全域性)物件。所以需要宣告一個_this變數,用來保證setInterval()可以改變Vue例項中的a的值。
顯示{{}},不進行替換
如果想顯示{{}}標籤,而不進行替換,可以使用v-pre,就可以跳過這個元素和它的子元素的編譯過程。
<div id="app">
<div>{{a}}
<sapn>{{b}}</sapn>
</div>
<div v-pre>{{a}}
<sapn>{{b}}</sapn>
</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
a: "你好!",
b: "Hello!"
},
});
</script>
渲染結果為:
<div id="app">
<div>你好!
<sapn>Hello!</sapn>
</div>
<div>{{a}}
<sapn>{{b}}</sapn>
</div>
</div>
2.HTML程式碼插值
如果有時候想輸出HTML程式碼,可以使用v-html:
<div id="app">
<div v-html="a"></div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
a: "<span>你好!</span>"
},
});
</script>
渲染後的結果為:
<div id="app">
<div><span>你好!</span></div>
</div>
3.雙大括號中表達式插值
在{{}}中,除了繫結屬性值外,還可以使用Javascript表示式進行簡單的運算、三元運算等:
<div id="app">
<div>{{message+1}}</div>
<div>{{right ? "yes":"no"}}</div>
<div>{{string+" world!"}}</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: 1,
right: true,
string:"hello"
},
})
</script>
渲染結果為:
<div id="app">
<div>2</div>
<div>yes</div>
<div>hello world!</div>
</div>
4.過濾器
可以在{{}}插值的尾部新增一個管道符號"|",對資料進行過濾。過濾的規則通過給Vue例項新增filters選項來設定:
<div id="app">
<div>{{a|toUp}}</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
a: "aBcdeFg"
},
filters: {
toUp: function (value) {//這裡的value是a資料本身
return value.toUpperCase();
}
}
});
</script>
上面的程式碼中,通過過濾器,將字串中的字母都變為大寫。
渲染結果為:
<div id="app">
<div>ABCDEFG</div>
</div>
過濾器可以串聯,也可以接收除了資料本身以外的引數:
<div>{{a|filter1|filter2}}</div>
<div>{{a|filter("arg1","arg2")}}</div>
傳入"arg1"和"arg2"將作為傳遞給過濾器的第二和第三個引數,因為過濾器的第一個引數是資料本身。
要注意過濾器屬於簡單的轉換,要實現更復雜的資料處理,應該使用下一篇文章中介紹的計算屬性。
5.Object.freeze()阻止修改現有的屬性
Object.freeze()使凍結的物件不能新增、修改屬性,也不能刪除某個屬性:
var obj={
a: 1
};
Object.freeze(obj);
obj.a=11;
console.log(obj.a);//1
obj.b=2;
console.log(obj.b);//undefined
delete obj.a;
console.log(obj.a);//1
在Vue中使用Object.freeze()
沒有凍結物件時:
var app = new Vue({
el: "#app",
data: {
a: 1
}
});
console.log(app.a);//1
app.a=11;
console.log(app.a);//11
使用Object.freeze()凍結物件之後,修改app.a的值會報錯:
var app = new Vue({
el: "#app",
data: Object.freeze({
a: 1
}),
});
console.log(app.a);//1
app.a=11;
//Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'
凍結已有變數
var obj={
a: 1
};
Object.freeze(obj);
var app = new Vue({
el: "#app",
data:obj,
});
console.log(app.a);//1
obj.a=2;
console.log(app.a);//1
在這裡,我發現了一個比較好玩的事情,把 Object.freeze(obj)放在構造Vue例項之後,就不會起作用了:
var obj={
a: 1
};
var app = new Vue({
el: "#app",
data:obj,
});
Object.freeze(obj);
console.log(app.a);//1
obj.a=2;
console.log(app.a);//2
這個的原因是什麼,我還沒有搞清楚,如果有哪位大神可以指導一下,非常感謝!
參考:
1.Vue.js官方文件
2.《Vue.js實戰》