一、v-bind 初探
它是一個(gè) vue 指令,用于綁定 html 屬性,如下:
<div id="app">
<p v-bind:title="title">html屬性不能使用雙大括號(hào)形式綁定谈为,只能使用v-bind指令</p>
</div>
......
var vm = new Vue({
el: '#app',
data: {
title: 'title content'
}
});
這里的 html 最后會(huì)渲染成:
<div id="app">
<p title="title content">html屬性不能使用雙大括號(hào)形式綁定,只能使用v-bind指令</p>
</div>
二踢关、指令預(yù)期值
上面這種 v-bind
這也是我們對(duì)于 vue 指令最初的理解伞鲫,但實(shí)際上,vue 指令的預(yù)期值(如 v-bind:class="classProperty"
中签舞,v-bind
是指令秕脓,:
后面的 class
是參數(shù),而 classProperty
則在官方文檔中被稱為“預(yù)期值”)儒搭,除了像上面那樣綁定一個(gè)字符串類型變量吠架,其實(shí)它是支持一個(gè)單一 JavaScript 表達(dá)式 (v-for
除外)。
所以在這里师妙,我們就可以有更多的選擇诵肛,例如:
(1)執(zhí)行運(yùn)算
<div id="app">
<p v-bind:title="t1 + ' ' + t2">html屬性不能使用雙大括號(hào)形式綁定,只能使用v-bind指令</p>
</div>
......
var vm = new Vue({
el: '#app',
data: {
t1: 'title1',
t2: 'title2'
}
});
最后渲染的結(jié)果:
<div id="app">
<p title="title1 title2">html屬性不能使用雙大括號(hào)形式綁定默穴,只能使用v-bind指令</p>
</div>
(2)執(zhí)行函數(shù)等
<div id="app">
<p v-bind:title="getTitle()">html屬性不能使用雙大括號(hào)形式綁定怔檩,只能使用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屬性不能使用雙大括號(hào)形式綁定,只能使用v-bind指令</p>
</div>
三蓄诽、支持的數(shù)據(jù)類型
上面的內(nèi)容薛训,指令預(yù)期值得到的都是字符串類型的數(shù)據(jù),但實(shí)際上仑氛,我們知道 js 有很多數(shù)據(jù)類型乙埃,它如果放入其中呢?
(1)對(duì)象類型
<div id="app">
<p v-bind:title="obj">content</p>
</div>
......
var obj = {};
var vm = new Vue({
el: '#app',
data: {
obj: obj
}
});
為什么一來(lái)就選擇對(duì)象類型呢锯岖?答案是它比較有代表性介袜,它渲染結(jié)果如下:
<div id="app">
<p title="[object Object]">content</p>
</div>
誒,這個(gè)怎么有點(diǎn)眼熟出吹?有點(diǎn)像...沒錯(cuò)遇伞!對(duì)象的 toString 方法的返回值!為了驗(yàn)證我們的猜想捶牢,我們進(jìn)行進(jìn)一步的測(cè)試:
<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
}
});
上面這里修改了 obj
的 toString
方法(但準(zhǔn)確的說(shuō)鸠珠,這里不是修改,而是添加秋麸。一開始的 obj
對(duì)象上自身是沒有 toString
方法的渐排,它繼承了 Object.prototype.toString
,但這里我們執(zhí)行 obj.toString = function.....
實(shí)際上是為它添加了一個(gè) toString
方法灸蟆,使得它執(zhí)行的時(shí)候驯耻,不用再去調(diào)用繼承自 Object
的方法),渲染結(jié)果如下:
<div id="app">
<p title="edited in toString!">content</p>
</div>
這里就進(jìn)一步證實(shí)了我們的猜想。
(2)數(shù)組類型
數(shù)組類型的 toString
方法和對(duì)象類型的有所不同可缚,它將返回和執(zhí)行 arr.join(',')
相同的結(jié)果孽水。如 [1, 2, 3].toString()
將返回 “1,2,3”。下面進(jìn)行測(cè)試:
<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>
仍然跟預(yù)期結(jié)果一樣城看。
(3)其它類型
- number 類型,正常執(zhí)行
toString
杏慰,包括數(shù)字0测柠,結(jié)果都正常渲染成對(duì)應(yīng)的字符串; - boolean 類型缘滥,
true
正常渲染成字符串"true"
轰胁,但false
雖然執(zhí)行toString
方法將返回"false"
字符串,但是卻沒有渲染出來(lái)朝扼; - null / undefined 類型赃阀,二者沒有
toString
方法,也沒有渲染出來(lái)擎颖。
顯然榛斯,在執(zhí)行toString
方法之前,vue 內(nèi)部應(yīng)該先做了類型校驗(yàn)搂捧,滿足條件才輸出驮俗。而且這里不是簡(jiǎn)單的真 / 假值校驗(yàn),因?yàn)?允跑、0
雖為假值王凑,但最終卻像真值一樣渲染了出來(lái)。具體如何實(shí)現(xiàn)聋丝,可能需要參考 vue 的源碼了索烹,這里不再深究。
四弱睦、多 html 屬性值綁定
一個(gè)的 html 屬性值百姓,可能包含許多內(nèi)容,需要我們進(jìn)行一些操作每篷,將多個(gè)數(shù)據(jù)綁定到一個(gè)屬性上瓣戚,這里我們可以考慮像前面一樣,通過(guò)如 “+” 等運(yùn)算符號(hào)等實(shí)現(xiàn)字符串的連接操作焦读。但是事實(shí)上子库,字符串連接麻煩又易錯(cuò),不易于維護(hù)矗晃。于是我們可以考慮像前面一樣向指令預(yù)期值中存入一個(gè)對(duì)象或數(shù)組仑嗅,來(lái)實(shí)現(xiàn)多個(gè)數(shù)據(jù)綁定到一個(gè)屬性上的作用。
(1)利用對(duì)象綁定
<div id="app">
<p v-bind:title="obj">content</p>
</div>
......
var obj = {
name: 'Dale',
age: 22
};
// 利用 for-in 循環(huán)遍歷對(duì)象屬性,拼接成字符串
obj.toString = function () {
var str = '';
for(var i in this) {
str += i + ': ' + this[i] + '; ';
}
return str;
};
// 防止 toString 方法自身被遍歷出來(lái)
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>
上面通過(guò) for-in 循環(huán)在 toString
方法中得到所有可遍歷的屬性以及對(duì)應(yīng)的屬性值仓技,然后將其拼接成字符串再進(jìn)行輸出鸵贬,可以實(shí)現(xiàn)多屬性值綁定,至于如何拼接脖捻,可以自己在 toString
方法中進(jìn)行不同的實(shí)現(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>
相比于對(duì)象字符串拼接,數(shù)組的拼接操作則顯得簡(jiǎn)單得多地沮,可以直接在 toString
方法返回 join
方法的返回值嗜浮,默認(rèn)的 toString
方法的返回值其實(shí)就和 join(',')
的返回值相同。
(3)思考
其實(shí)想想一個(gè) html 屬性綁定多個(gè)值的情況其實(shí)并不少見摩疑,最典型的應(yīng)該是 class
和 style
屬性危融,或者說(shuō)我們經(jīng)常都會(huì)接觸到這樣的場(chǎng)景。
但我們這里的實(shí)現(xiàn)雷袋,看起來(lái)還是問(wèn)題比較多吉殃,數(shù)組的綁定還好,對(duì)象的綁定楷怒,除了每次要重寫 toString
方法以外蛋勺,我們還需要設(shè)置 toString
方法變得不可枚舉,否則它將在 for-in 循環(huán)中被遍歷出來(lái)(一般情況下率寡,這不是我們希望看到的結(jié)果)迫卢,這樣無(wú)疑會(huì)增加很多重復(fù)性工作,而 vue 為我們考慮到了這一點(diǎn)冶共,它在框架內(nèi)部進(jìn)行了一些優(yōu)化操作乾蛤。
五、vue 對(duì)于 class
和 style
綁定的增強(qiáng)
基于上面的情況捅僵,vue 對(duì) class
和 style
這兩個(gè) html 屬性進(jìn)行了一定程度的增強(qiáng)家卖。vue 具體的實(shí)現(xiàn)方式請(qǐng)參考其源碼,這里僅給出基于上面的結(jié)論的實(shí)現(xiàn)方式庙楚。
(1)基于對(duì)象針對(duì) class
的增強(qiáng)
<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 方法自身被遍歷出來(lái)
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上荡,與之前不同的是,當(dāng)檢測(cè)到 obj
的某個(gè)屬性值為真的時(shí)候馒闷,則將這個(gè)屬性的屬性名添加到綁定的元素的 class
上酪捡。當(dāng)然,我這里只是一個(gè)模擬實(shí)現(xiàn)纳账,vue 實(shí)際的實(shí)現(xiàn)方式逛薇,請(qǐng)參考 vue 源碼。
(2)基于數(shù)組對(duì) class
的增強(qiáng)
<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>
這里基本和前面的實(shí)現(xiàn)思路一樣疏虫,利用 join(' ')
實(shí)現(xiàn)永罚。
(3)基于對(duì)象對(duì) style
的增強(qiáng)
<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 方法自身被遍歷出來(lái)
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>
這里基本和前面的實(shí)現(xiàn)思路一樣啤呼,利用 for-in 配合字符串拼接實(shí)現(xiàn)。
(4)基于數(shù)組對(duì) style
的增強(qiáng)
<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>
這里通過(guò) forEach
方法遍歷了數(shù)組呢袱,然后將數(shù)組元素(也就是這里我們的樣式對(duì)象)再通過(guò) for-in 遍歷并拼接成樣式字符串達(dá)到效果官扣。
六、結(jié)語(yǔ)
再次強(qiáng)調(diào)羞福,這里只是個(gè)人的理解和思考惕蹄,僅供參考,vue 本身的實(shí)現(xiàn)方式未必相同治专,如果有需要焊唬,請(qǐng)參考 vue 源碼。