<div> <p v-bind:title="obj">content</p> </div> ...... var obj = { name: 'Dale', age: 22 }; // 利用 for-in 循环遍历对象属性,拼接成字符串 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 } });
输出结果:
<div> <p title="name: Dale; age: 22; ">content</p> </div>
上面通过 for-in 循环在 toString 方法中得到所有可遍历的属性以及对应的属性值,然后将其拼接成字符串再进行输出,可以实现多属性值绑定,至于如何拼接,可以自己在 toString 方法中进行不同的实现 。
(2)利用数组绑定
<div> <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 } });
渲染结果如下:
<div> <p title="1 2 3">content</p> </div>
相比于对象字符串拼接,数组的拼接操作则显得简单得多,可以直接在 toString 方法返回 join 方法的返回值,默认的 toString 方法的返回值其实就和 join(',') 的返回值相同。
(3)思考
其实想想一个 html 属性绑定多个值的情况其实并不少见,最典型的应该是 class 和 style 属性,或者说我们经常都会接触到这样的场景。
但我们这里的实现,看起来还是问题比较多,数组的绑定还好,对象的绑定,除了每次要重写 toString 方法以外,我们还需要设置 toString 方法变得不可枚举,否则它将在 for-in 循环中被遍历出来(一般情况下,这不是我们希望看到的结果),这样无疑会增加很多重复性工作,而 vue 为我们考虑到了这一点,它在框架内部进行了一些优化操作。
五、vue 对于 class 和 style 绑定的增强
基于上面的情况,vue 对 class 和 style 这两个 html 属性进行了一定程度的增强。vue 具体的实现方式请参考其源码,这里仅给出基于上面的结论的实现方式。
(1)基于对象针对 class 的增强
<div> <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 } });
渲染结果:
<div> <p>content</p> </div>
同样是 for-in,与之前不同的是,当检测到 obj 的某个属性值为真的时候,则将这个属性的属性名添加到绑定的元素的 class 上。当然,我这里只是一个模拟实现,vue 实际的实现方式,请参考 vue 源码。
(2)基于数组对 class 的增强
<div> <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 } });
渲染结果:
<div> <p>content</p> </div>
这里基本和前面的实现思路一样,利用 join(' ') 实现。
(3)基于对象对 style 的增强
<div> <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 } });
渲染结果:
<div> <p>content</p> </div>
这里基本和前面的实现思路一样,利用 for-in 配合字符串拼接实现。
(4)基于数组对 style 的增强
<div> <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 } });
渲染结果:
<div> <p>content</p> </div>
这里通过 forEach 方法遍历了数组,然后将数组元素(也就是这里我们的样式对象)再通过 for-in 遍历并拼接成样式字符串达到效果。
六、结语
再次强调,这里只是个人的理解和思考,仅供参考,vue 本身的实现方式未必相同。