关于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 相关文章推荐
JQuery最佳实践之精妙的自定义事件
Aug 11 Javascript
JS运行耗时操作的延时显示方法
Nov 19 Javascript
通过js获取div的background-image属性
Oct 15 Javascript
Egret引擎开发指南之发布项目
Sep 03 Javascript
JavaScript获取一个范围内日期的方法
Apr 24 Javascript
bootstrap datetimepicker实现秒钟选择下拉框
Jan 05 Javascript
vuejs实现递归树型菜单组件
Jan 13 Javascript
vue-cli+webpack项目 修改项目名称的方法
Feb 28 Javascript
js实现京东秒杀倒计时功能
Jan 21 Javascript
前端面试知识点目录一览
Apr 15 Javascript
微信小程序实现图片上传
May 23 Javascript
Vue computed 计算属性代码实例
Apr 22 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
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
CodeIgniter框架过滤HTML危险代码
2014/06/12 PHP
PHP中isset与array_key_exists的区别实例分析
2015/06/02 PHP
php函数连续调用实例分析
2015/07/30 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
Laravel如何同时连接多个数据库详解
2019/08/13 PHP
laravel框架中控制器的创建和使用方法分析
2019/11/23 PHP
tp5.1 框架数据库高级查询技巧实例总结
2020/05/25 PHP
javascript 弹出层组件(升级版)
2011/05/12 Javascript
JavaScript 布尔操作符解析  &amp;&amp; || !
2012/08/10 Javascript
用js格式化金额可设置保留的小数位数
2014/05/09 Javascript
一个用jquery写的判断div滚动条到底部的方法【推荐】
2016/04/29 Javascript
Javascript缓存API
2016/06/14 Javascript
node.js平台下利用cookie实现记住密码登陆(Express+Ejs+Mysql)
2017/04/26 Javascript
详解js静态检查工具eslint配置文件
2018/11/23 Javascript
vue实现给div绑定keyup的enter事件
2020/07/31 Javascript
[04:03]DOTA2英雄梦之声_第02期_风暴之灵
2014/06/30 DOTA
Python Web程序部署到Ubuntu服务器上的方法
2018/02/22 Python
python中计算一个列表中连续相同的元素个数方法
2018/06/29 Python
用Python实现大文本文件切割的方法
2019/01/12 Python
简单瞅瞅Python vars()内置函数的实现
2019/09/27 Python
django从后台返回html代码的实例
2020/03/11 Python
jupyternotebook 撤销删除的操作方式
2020/04/17 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
CSS3实现同时执行倾斜和旋转的动画效果
2016/10/27 HTML / CSS
英国度假别墅预订:Sykes Cottages
2017/06/12 全球购物
传播学专业毕业生自荐信
2013/11/04 职场文书
大客户销售经理职责
2013/12/04 职场文书
给民警的表扬信
2014/01/08 职场文书
校园安全标语
2014/06/07 职场文书
2014卖家双十一活动策划书
2014/09/29 职场文书
机关党员四风问题个人整改措施
2014/10/26 职场文书
个人工作决心书
2015/09/22 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书
Nginx配置https原理及实现过程详解
2021/03/31 Servers
Python中Matplotlib的点、线形状、颜色以及绘制散点图
2022/04/07 Python