关于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 相关文章推荐
Iframe自适应高度绝对好使的代码 兼容IE,遨游,火狐
Jan 27 Javascript
Javascript中自动切换焦点实现代码
Dec 15 Javascript
js实现两个值相加alert出来精确到指定位
Sep 25 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
Jun 09 Javascript
jquery判断复选框是否选中进行答题提示特效
Dec 10 Javascript
jquery把int类型转换成字符串类型的方法
Oct 07 Javascript
利用angular.copy取消变量的双向绑定与解析
Nov 25 Javascript
javascript history对象详解
Feb 09 Javascript
vue2 mint-ui loadmore实现下拉刷新,上拉更多功能
Mar 21 Javascript
Angular数据绑定机制原理
Apr 17 Javascript
详解vue中router-link标签所必备了解的属性
Apr 15 Javascript
原生js滑动轮播封装
Jul 31 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
六酷社区论坛HOME页清新格调免费版 下载
2007/03/07 PHP
15种PHP Encoder的比较
2007/04/17 PHP
phpmyadmin导入(import)文件限制的解决办法
2009/12/11 PHP
php一行代码获取文件后缀名实例分析
2014/11/12 PHP
php中namespace及use用法分析
2016/12/06 PHP
php中的异常和错误浅析
2017/05/03 PHP
php中各种定义变量的方法小结
2017/10/18 PHP
php实现生成PDF文件的方法示例【基于FPDF类库】
2018/07/21 PHP
javascript:以前写的xmlhttp池,代码
2008/05/18 Javascript
JQuery live函数
2010/12/24 Javascript
使用JS 清空File控件的路径值
2013/07/08 Javascript
使用JavaScript实现Java的List功能(实例讲解)
2013/11/07 Javascript
利用js正则表达式验证手机号,email地址,邮政编码
2014/01/23 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
2014/12/16 Javascript
JavaScript中的函数模式详解
2015/02/11 Javascript
js 提交form表单和设置form表单请求路径的实现方法
2016/10/25 Javascript
浅谈javascript alert和confirm的美化
2016/12/15 Javascript
JS实现图片手风琴效果
2020/04/17 Javascript
详解Axios统一错误处理与后置
2018/09/26 Javascript
《javascript设计模式》学习笔记五:Javascript面向对象程序设计工厂模式实例分析
2020/04/08 Javascript
js实现点击选项置顶动画效果
2020/08/25 Javascript
Python常用内置模块之xml模块(详解)
2017/05/23 Python
Python3.X 线程中信号量的使用方法示例
2017/07/24 Python
python+opencv识别图片中的圆形
2020/03/25 Python
Python实现的多进程和多线程功能示例
2018/05/29 Python
wxpython布局的实现方法
2019/11/01 Python
关于numpy数组轴的使用详解
2019/12/05 Python
django连接mysql数据库及建表操作实例详解
2019/12/10 Python
iframe在移动端的缩放的示例代码
2018/10/12 HTML / CSS
StubHub意大利:购买和出售全球演唱会和体育赛事门票
2017/11/21 全球购物
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?用contains来区分是否有重复的对象。还是都不用
2013/07/30 面试题
VLAN和VPN有什么区别?分别实现在OSI的第几层?
2014/12/23 面试题
Delphi工程师笔试题
2013/09/21 面试题
小学捐书活动总结
2014/07/05 职场文书
出资证明书范本(标准版)
2014/09/24 职场文书
教师四风问题整改措施
2014/09/25 职场文书