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


Posted in Javascript onJune 06, 2017

一、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 是参数,而 classProperty 则在官方文档中被称为“预期值”),除了像上面那样绑定一个字符串类型变量,其实它是支持一个单一 JavaScript 表达式 (v-for 除外)。
所以在这里,我们就可以有更多的选择,例如:

(1)执行运算

<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'
  }
});

最后渲染的结果:

<div id="app">
  <p title="title1 title2">html属性不能使用双大括号形式绑定,只能使用v-bind指令</p>
</div>

(2)执行函数等

<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';
    }
  }
});

最后渲染的结果:

<div id="app">
  <p title="title content">html属性不能使用双大括号形式绑定,只能使用v-bind指令</p>
</div>

三、支持的数据类型

上面的内容,指令预期值得到的都是字符串类型的数据,但实际上,我们知道 js 有很多数据类型,它如果放入其中呢?

(1)对象类型

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

为什么一来就选择对象类型呢?答案是它比较有代表性,它渲染结果如下:

<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
  }
});

上面这里修改了 obj 的  toString 方法(但准确的说,这里不是修改,而是添加。一开始的 obj 对象上自身是没有 toString 方法的,它继承了 Object.prototype.toString,但这里我们执行 obj.toString  = function..... 实际上是为它添加了一个 toString 方法,使得它执行的时候,不用再去调用继承自 Object 的方法),渲染结果如下:

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

这里就进一步证实了我们的猜想。

(2)数组类型

数组类型的 toString 方法和对象类型的有所不同,它将返回和执行 arr.join(',') 相同的结果。如 [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]
  }
});

渲染结果如下:

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

仍然跟预期结果一样。

(3)其它类型

  1. number 类型,正常执行 toString,包括数字0,结果都正常渲染成对应的字符串;
  2. boolean 类型,true 正常渲染成字符串 "true",但 false 虽然执行 toString 方法将返回 "false" 字符串,但是却没有渲染出来;
  3. null / undefined 类型,二者没有 toString 方法,也没有渲染出来。

显然,在执行 toString 方法之前,vue 内部应该先做了类型校验,满足条件才输出。而且这里不是简单的真 / 假值校验,因为 、0 虽为假值,但最终却像真值一样渲染了出来。具体如何实现,可能需要参考 vue 的源码了,这里不再深究。

四、多 html 属性值绑

一个的 html 属性值,可能包含许多内容,需要我们进行一些操作,将多个数据绑定到一个属性上,这里我们可以考虑像前面一样,通过如 “+” 等运算符号等实现字符串的连接操作。但是事实上,字符串连接麻烦又易错,不易于维护。于是我们可以考虑像前面一样向指令预期值中存入一个对象或数组,来实现多个数据绑定到一个属性上的作用。

(1)利用对象绑定

<div id="app">
  <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 id="app">
  <p title="name: Dale; age: 22; ">content</p>
</div>

上面通过 for-in 循环在 toString 方法中得到所有可遍历的属性以及对应的属性值,然后将其拼接成字符串再进行输出,可以实现多属性值绑定,至于如何拼接,可以自己在 toString 方法中进行不同的实现 。

(2)利用数组绑定

<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
  }
});

渲染结果如下:

<div id="app">
  <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 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
  }
});

渲染结果:

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

同样是 for-in,与之前不同的是,当检测到 obj 的某个属性值为真的时候,则将这个属性的属性名添加到绑定的元素的 class 上。当然,我这里只是一个模拟实现,vue 实际的实现方式,请参考 vue 源码。

(2)基于数组对 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
  }
});

渲染结果:

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

这里基本和前面的实现思路一样,利用 join(' ') 实现。

(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
  }
});

渲染结果:

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

这里基本和前面的实现思路一样,利用 for-in 配合字符串拼接实现。

(4)基于数组对 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
  }
});

渲染结果:

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

这里通过 forEach 方法遍历了数组,然后将数组元素(也就是这里我们的样式对象)再通过 for-in 遍历并拼接成样式字符串达到效果。

六、结语

再次强调,这里只是个人的理解和思考,仅供参考,vue 本身的实现方式未必相同。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
图片自动更新(说明)
Oct 02 Javascript
jquery 应用代码 方便的排序功能
Feb 06 Javascript
浅析Prototype的模板类 Template
Dec 07 Javascript
window.open()实现post传递参数
Mar 12 Javascript
解决angular的post请求后SpringMVC后台接收不到参数值问题的方法
Dec 10 Javascript
AugularJS从入门到实践(必看篇)
Jul 10 Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
May 18 Javascript
详解Vue改变数组中对象的属性不重新渲染View的解决方案
Sep 21 Javascript
JS实现简单的表格增删
Jan 16 Javascript
js实现mp3录音通过websocket实时传送+简易波形图效果
Jun 12 Javascript
vue实践---根据不同环境,自动转换请求的url地址操作
Sep 21 Javascript
vue中data改变后让视图同步更新的方法
Mar 29 Vue.js
详解vue-cli开发环境跨域问题解决方案
Jun 06 #Javascript
JS实现微信里判断页面是否被分享成功的方法
Jun 06 #Javascript
详解Vue 开发模式下跨域问题
Jun 06 #Javascript
JS实现经典的中国地区三级联动下拉菜单功能实例【测试可用】
Jun 06 #Javascript
深入理解vue-loader如何使用
Jun 06 #Javascript
利用webstrom调试Vue.js单页面程序的方法教程
Jun 06 #Javascript
JavaScript实现一个空中避难的小游戏
Jun 06 #Javascript
You might like
极典R601SW收音机
2021/03/02 无线电
php采集文章中的图片获取替换到本地(实现代码)
2013/07/08 PHP
PHP实现微信发红包程序
2015/08/24 PHP
PHP 设计模式系列之 specification规格模式
2016/01/10 PHP
php 输出json及显示json中的中文汉字详解及实例
2016/11/09 PHP
用Div仿showModalDialog模式菜单的效果的代码
2007/03/05 Javascript
JavaScript学习笔记之数组随机排序
2016/03/23 Javascript
Three.js实现浏览器变动时进行自适应的方法
2017/09/26 Javascript
vue 通过下拉框组件学习vue中的父子通讯
2017/12/19 Javascript
超出JavaScript安全整数限制的数字计算BigInt详解
2018/06/24 Javascript
VUE中v-on:click事件中获取当前dom元素的代码
2018/08/22 Javascript
ng-repeat指令在迭代对象时的去重方法
2018/10/02 Javascript
小程序自定义单页面、全局导航栏的实现代码
2019/03/15 Javascript
详解如何写出一个利于扩展的vue路由配置
2019/05/16 Javascript
解决Vue动态加载本地图片问题
2019/10/09 Javascript
vue项目打包后提交到git上为什么没有dist这个文件的解决方法
2020/09/16 Javascript
JavaScript语法约定和程序调试原理解析
2020/11/03 Javascript
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
python网络编程学习笔记(三):socket网络服务器
2014/06/09 Python
使用Python发送邮件附件以定时备份MySQL的教程
2015/04/25 Python
CentOS 7下安装Python 3.5并与Python2.7兼容并存详解
2017/07/07 Python
python基于ID3思想的决策树
2018/01/03 Python
Pycharm 字体大小调整设置的方法实现
2019/09/27 Python
python使用opencv实现马赛克效果示例
2019/09/28 Python
python异常处理之try finally不报错的原因
2020/05/18 Python
Python实现爬取网页中动态加载的数据
2020/08/17 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
pycharm-professional-2020.1下载与激活的教程
2020/09/21 Python
python中Mako库实例用法
2020/12/31 Python
手把手教你配置JupyterLab 环境的实现
2021/02/02 Python
css3进阶之less实现星空动画的示例代码
2019/09/10 HTML / CSS
酒店办公室文员岗位职责
2013/12/18 职场文书
探亲邀请信范文
2014/01/30 职场文书
甜品蛋糕店创业计划书
2014/09/21 职场文书
Vue项目中如何封装axios(统一管理http请求)
2021/05/02 Vue.js
Spring Boot项目传参校验的最佳实践指南
2022/04/05 Java/Android