关于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 相关文章推荐
显示、隐藏密码
Jul 01 Javascript
JavaScript获取多个数组的交集简单实例
Nov 11 Javascript
JavaScript中使用Math.floor()方法对数字取整
Jun 15 Javascript
jQuery实现瀑布流布局详解(PC和移动端)
Sep 01 Javascript
JavaScript操作XML/HTML比较常用的对象属性集锦
Oct 30 Javascript
详解JavaScript对象类型
Jun 16 Javascript
微信小程序实现移动端滑动分页效果(ajax)
Jun 13 Javascript
基于jQuery实现定位导航位置效果
Nov 15 jQuery
jQuery实现form表单序列化转换为json对象功能示例
May 23 jQuery
react native基于FlatList下拉刷新上拉加载实现代码示例
Sep 30 Javascript
深入理解Puppeteer的入门教程和实践
Mar 05 Javascript
JS定义函数的几种常用方法小结
May 23 Javascript
详解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
日本因肺炎疫情影响,这几部动漫推延播放!
2020/03/03 日漫
PHP nl2br函数 将换行字符转成 &amp;lt;br&amp;gt;
2009/08/21 PHP
destoon复制新模块的方法
2014/06/21 PHP
ThinkPHP采用GET方式获取中文参数查询无结果的解决方法
2014/06/26 PHP
php mysql 封装类实例代码
2016/09/18 PHP
highchart数据源纵轴json内的值必须是int(详解)
2017/02/20 PHP
基于thinkphp6.0的success、error实现方法
2019/11/05 PHP
用函数式编程技术编写优美的 JavaScript
2006/11/25 Javascript
JavaScript 异步调用框架 (Part 4 - 链式调用)
2009/08/04 Javascript
js 返回时间戳所对应的具体时间
2010/07/20 Javascript
Extjs gridpanel 出现横向滚动条问题的解决方法
2011/07/04 Javascript
Vue表单实例代码
2016/09/05 Javascript
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
2016/12/14 Javascript
AngularJS学习第一篇 AngularJS基础知识
2017/02/13 Javascript
微信小程序 连续旋转动画(this.animation.rotate)详解
2017/04/07 Javascript
JavaScript对JSON数据进行排序和搜索
2017/07/24 Javascript
Angularjs中的验证input输入框只能输入数字和小数点的写法(推荐)
2017/08/16 Javascript
Windows下Node.js安装及环境配置方法
2017/09/18 Javascript
vue父组件触发事件改变子组件的值的方法实例详解
2019/05/07 Javascript
如何在vue项目中嵌入jsp页面的方法(2种)
2020/02/06 Javascript
python实现定制交互式命令行的方法
2014/07/03 Python
Windows8下安装Python的BeautifulSoup
2015/01/22 Python
python实现守护进程、守护线程、守护非守护并行
2018/05/05 Python
在python下使用tensorflow判断是否存在文件夹的实例
2019/06/10 Python
解决Django提交表单报错:CSRF token missing or incorrect的问题
2020/03/13 Python
ubuntu 安装pyqt5和卸载pyQt5的方法
2020/03/24 Python
html5页面结构_动力节点Java学院整理
2017/07/10 HTML / CSS
英语专业学子个人的自我评价
2013/10/02 职场文书
安全演讲稿大全
2014/05/09 职场文书
物业管理工作方案
2014/05/10 职场文书
交通安全责任书范本
2014/07/24 职场文书
承诺函范文
2015/01/21 职场文书
优秀毕业生主要事迹材料
2015/11/04 职场文书
Go timer如何调度
2021/06/09 Golang
MySQL 1130异常,无法远程登录解决方案详解
2021/08/23 MySQL
使用Apache Camel表达REST服务的方法
2022/06/10 Servers