1. 程式人生 > >Vue 建構函式、生命週期與資料雙向繫結

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實戰》