vue.js - v-bind 的一些理解和思考

一、v-bind 初探

它是一個 vue 指令,用于綁定 html 屬性,如下:

<div id="app">
    <p v-bind:title="title">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>
......
var vm = new Vue({
    el: '#app',
    data: {
        title: 'title content'
    }
});

這里的 html 最后會渲染成:

<div id="app">
    <p title="title content">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>

二、指令預期值

上面這種 v-bind 這也是我們對于 vue 指令最初的理解,但實際上,vue 指令的預期值(如 v-bind:class="classProperty" 中,v-bind 是指令,: 后面的 class 是參數(shù),而 classProperty 則在官方文檔中被稱為“預期值”),除了像上面那樣綁定一個字符串類型變量,其實它是支持一個單一 JavaScript 表達式v-for 除外)。
所以在這里,我們就可以有更多的選擇,例如:

(1)執(zhí)行運算

<div id="app">
    <p v-bind:title="t1 + ' ' + t2">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>
......
var vm = new Vue({
    el: '#app',
    data: {
        t1: 'title1',
        t2: 'title2'
    }
});

最后渲染的結(jié)果:

<div id="app">
    <p title="title1 title2">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>

(2)執(zhí)行函數(shù)等

<div id="app">
    <p v-bind:title="getTitle()">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>
......
var vm = new Vue({
    el: '#app',
    data: {
        getTitle: function () {
            return 'title content';
        }
    }
});

最后渲染的結(jié)果:

<div id="app">
    <p title="title content">html屬性不能使用雙大括號形式綁定,只能使用v-bind指令</p>
</div>

三、支持的數(shù)據(jù)類型

上面的內(nèi)容,指令預期值得到的都是字符串類型的數(shù)據(jù),但實際上,我們知道 js 有很多數(shù)據(jù)類型,它如果放入其中呢?

(1)對象類型

<div id="app">
    <p v-bind:title="obj">content</p>
</div>
......
var obj = {};
var vm = new Vue({
    el: '#app',
    data: {
        obj: obj
    }
});

為什么一來就選擇對象類型呢?答案是它比較有代表性,它渲染結(jié)果如下:

<div id="app">
    <p title="[object Object]">content</p>
</div>

誒,這個怎么有點眼熟?有點像...沒錯!對象的 toString 方法的返回值!為了驗證我們的猜想,我們進行進一步的測試:

<div id="app">
    <p v-bind:title="obj">content</p>
</div>
......
var obj = {};

obj.toString = function () {
    return 'edited in toString!';
};

var vm = new Vue({
    el: '#app',
    data: {
        obj: obj
    }
});

上面這里修改了 objtoString 方法(但準確的說,這里不是修改,而是添加。一開始的 obj 對象上自身是沒有 toString 方法的,它繼承了 Object.prototype.toString,但這里我們執(zhí)行 obj.toString = function..... 實際上是為它添加了一個 toString 方法,使得它執(zhí)行的時候,不用再去調(diào)用繼承自 Object 的方法),渲染結(jié)果如下:

<div id="app">
    <p title="edited in toString!">content</p>
</div>

這里就進一步證實了我們的猜想。

(2)數(shù)組類型

數(shù)組類型的 toString 方法和對象類型的有所不同,它將返回和執(zhí)行 arr.join(',') 相同的結(jié)果。如 [1, 2, 3].toString() 將返回 “1,2,3”。下面進行測試:

<div id="app">
    <p v-bind:title="arr">content</p>
</div>
......
var vm = new Vue({
    el: '#app',
    data: {
        arr: [1, 2, 3]
    }
});

渲染結(jié)果如下:

<div id="app">
    <p title="1,2,3">content</p>
</div>

仍然跟預期結(jié)果一樣。

(3)其它類型

  • number 類型,正常執(zhí)行 toString,包括數(shù)字0,結(jié)果都正常渲染成對應的字符串;
  • boolean 類型,true 正常渲染成字符串 "true",但 false 雖然執(zhí)行 toString 方法將返回 "false" 字符串,但是卻沒有渲染出來;
  • null / undefined 類型,二者沒有 toString 方法,也沒有渲染出來。
    顯然,在執(zhí)行 toString 方法之前,vue 內(nèi)部應該先做了類型校驗,滿足條件才輸出。而且這里不是簡單的真 / 假值校驗,因為 、0 雖為假值,但最終卻像真值一樣渲染了出來。具體如何實現(xiàn),可能需要參考 vue 的源碼了,這里不再深究。

四、多 html 屬性值綁定

一個的 html 屬性值,可能包含許多內(nèi)容,需要我們進行一些操作,將多個數(shù)據(jù)綁定到一個屬性上,這里我們可以考慮像前面一樣,通過如 “+” 等運算符號等實現(xiàn)字符串的連接操作。但是事實上,字符串連接麻煩又易錯,不易于維護。于是我們可以考慮像前面一樣向指令預期值中存入一個對象或數(shù)組,來實現(xiàn)多個數(shù)據(jù)綁定到一個屬性上的作用。

(1)利用對象綁定

<div id="app">
    <p v-bind:title="obj">content</p>
</div>
......
var obj = {
    name: 'Dale',
    age: 22
};

// 利用 for-in 循環(huán)遍歷對象屬性,拼接成字符串
obj.toString = function () {
    var str = '';
    for(var i in this) {
        str += i + ': ' + this[i] + '; ';
    }
    return str;
};

// 防止 toString 方法自身被遍歷出來
Object.defineProperty(obj, 'toString', {'enumerable': false});

var vm = new Vue({
    el: '#app',
    data: {
        obj: obj
    }
});

輸出結(jié)果:

<div id="app">
    <p title="name: Dale; age: 22; ">content</p>
</div>

上面通過 for-in 循環(huán)在 toString 方法中得到所有可遍歷的屬性以及對應的屬性值,然后將其拼接成字符串再進行輸出,可以實現(xiàn)多屬性值綁定,至于如何拼接,可以自己在 toString 方法中進行不同的實現(xiàn) 。

(2)利用數(shù)組綁定

<div id="app">
    <p v-bind:title="arr">content</p>
</div>
......
var arr = [1, 2, 3];

arr.toString = function () {
    return this.join(' ');
};

var vm = new Vue({
    el: '#app',
    data: {
        arr: arr
    }
});

渲染結(jié)果如下:

<div id="app">
    <p title="1 2 3">content</p>
</div>

相比于對象字符串拼接,數(shù)組的拼接操作則顯得簡單得多,可以直接在 toString 方法返回 join 方法的返回值,默認的 toString 方法的返回值其實就和 join(',') 的返回值相同。

(3)思考

其實想想一個 html 屬性綁定多個值的情況其實并不少見,最典型的應該是 classstyle 屬性,或者說我們經(jīng)常都會接觸到這樣的場景。
但我們這里的實現(xiàn),看起來還是問題比較多,數(shù)組的綁定還好,對象的綁定,除了每次要重寫 toString 方法以外,我們還需要設置 toString 方法變得不可枚舉,否則它將在 for-in 循環(huán)中被遍歷出來(一般情況下,這不是我們希望看到的結(jié)果),這樣無疑會增加很多重復性工作,而 vue 為我們考慮到了這一點,它在框架內(nèi)部進行了一些優(yōu)化操作。

五、vue 對于 classstyle 綁定的增強

基于上面的情況,vue 對 classstyle 這兩個 html 屬性進行了一定程度的增強。vue 具體的實現(xiàn)方式請參考其源碼,這里僅給出基于上面的結(jié)論的實現(xiàn)方式。

(1)基于對象針對 class 的增強

<div id="app">
    <p v-bind:class="obj">content</p>
</div>
......
var obj = {
    c1: true,
    c2: false,
    c3: null,
    c4: undefined
};

obj.toString = function () {
    var str = '';
    for(var i in this) {
        if(this[i]) {
            str += i + ' ';
        }
    }

    return str;
};

// 防止 toString 方法自身被遍歷出來
Object.defineProperty(obj, 'toString', {'enumerable': false});

var vm = new Vue({
    el: '#app',
    data: {
        obj: obj
    }
});

渲染結(jié)果:

<div id="app">
    <p class="c1">content</p>
</div>

同樣是 for-in,與之前不同的是,當檢測到 obj 的某個屬性值為真的時候,則將這個屬性的屬性名添加到綁定的元素的 class 上。當然,我這里只是一個模擬實現(xiàn),vue 實際的實現(xiàn)方式,請參考 vue 源碼。

(2)基于數(shù)組對 class 的增強

<div id="app">
    <p v-bind:class="arr">content</p>
</div>
.......
var arr = ['c1', 'c2', 'c3'];

arr.toString = function () {
    return this.join(' ');
};

var vm = new Vue({
    el: '#app',
    data: {
        arr: arr
    }
});

渲染結(jié)果:

<div id="app">
    <p class="c1 c2 c3">content</p>
</div>

這里基本和前面的實現(xiàn)思路一樣,利用 join(' ') 實現(xiàn)。

(3)基于對象對 style 的增強

<div id="app">
    <p v-bind:style="obj">content</p>
</div>
......
var obj = {
    color: 'red',
    backgroundColor: '#ddd',
    fontSize: '20px',
};

obj.toString = function () {
    var str = '';
    for(var i in this) {
        if(this[i]) {
            str += i + ':' + this[i] + ';';
        }
    }

    return str;
};

// 防止 toString 方法自身被遍歷出來
Object.defineProperty(obj, 'toString', {'enumerable': false});

var vm = new Vue({
    el: '#app',
    data: {
        obj: obj
    }
});

渲染結(jié)果:

<div id="app">
    <p style="color: red; background-color: rgb(221, 221, 221); font-size: 20px;">content</p>
</div>

這里基本和前面的實現(xiàn)思路一樣,利用 for-in 配合字符串拼接實現(xiàn)。
(4)基于數(shù)組對 style 的增強

<div id="app">
    <p v-bind:style="arr">content</p>
</div>

<script>
var arr = [{
        color: "red"
    }, {
        backgroundColor: '#ddd'
    }, {
        fontSize: '20px'
    }];

arr.toString = function () {
    var str = '';
    arr.forEach(function (val, key) {
        for(var i in val) {
            str += i + ':' + val[i] + ';';
        }
    });
};

var vm = new Vue({
    el: '#app',
    data: {
        arr: arr
    }
});

渲染結(jié)果:

<div id="app">
    <p style="color: red; background-color: rgb(221, 221, 221); font-size: 20px;">content</p>
</div>

這里通過 forEach 方法遍歷了數(shù)組,然后將數(shù)組元素(也就是這里我們的樣式對象)再通過 for-in 遍歷并拼接成樣式字符串達到效果。

六、結(jié)語

再次強調(diào),這里只是個人的理解和思考,僅供參考,vue 本身的實現(xiàn)方式未必相同,如果有需要,請參考 vue 源碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,177評論 0 29
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學一百閱讀 3,679評論 0 4
  • 追星 原創(chuàng)文 | 是熱河 (清風浪港手寫鋪原創(chuàng)文,未經(jīng)授權(quán)請勿轉(zhuǎn)載) “如果這是我第一次見到你我肯的也會嚎啕大哭,...
    清風浪港手寫鋪閱讀 449評論 0 0
  • 這一段時間呆在天津,下午沒什么事做,挺無聊的,看了看,百度地圖,附近有個李叔同紀念館,頓時耳邊就響起了那個熟悉的旋...
    Anna夢非夢閱讀 598評論 7 6

友情鏈接更多精彩內(nèi)容