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

一、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 本身的实现方式未必相同。

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

(0)

相关推荐

  • 详解vue的数据binding绑定原理

    自从angular火了以后,各种mvc框架喷涌而出,angular虽然比较火,但是他的坑还是蛮多的,还有许多性能问题被人们吐槽.比如坑爹的脏检查机制,数据binding是受人喜爱的,脏检查就有点-性能低下了.有时候改了一个地方,脏循环要循环多次来保证数据是不是真的变了和是否停止变化了.这样性能就很低了.于是人们开始钻研新的双向数据binding的方法.尤大的vue binding就是本人蛮喜欢的一种实现方式,本文跟随尤大的一个例子来详解vue的数据binding的原理. 数据binding,一般

  • Vue.js中用v-bind绑定class的注意事项

    前言 在Vue.js版本:1.0.27,使用Vue.js中V-bind指令来绑定class和style时,Vue.js对其进行了增强.表达式结果出了字符串之外,还可以是对象或者数组. 这里自己对其进行了测试,发现有一下的问题: 如果使用对象语法对class进行绑定话,class名称必须加上引号,代表所对应的样式,否则会将其当做对象的属性,从而使得初始化报错. <!DOCTYPE html> <html lang="en"> <head> <me

  • vue学习笔记之指令v-text && v-html && v-bind详解

    一 : 指令的概念: 指令是vue自定义的以v-开头的自定义属性.每个不同的属性都有各自不同的意义和功能 二 : 指令的语法: v-指令名 = "表达式判断或者是业务模型中属性名或者事件名" 三 : 具体指令 1. v-text 作用 : 操作元素中的纯文本 快捷方式 : {{}} 栗子1 简写形式:将v-text=""换成{{}} <div id="app"> {{ message }} </div> var app =

  • 关于vue.js过渡css类名的理解(推荐)

    首先附上官方文档图. 总体就是在解释v-enter,v-enter-active,v-leave,v-leave-active的意思,但是我看了半天,就是看不懂,老是和鼠标的mouseover和mouseout事件联想在一起,在经过多方的查找,总算是理解了,以下就是我所理解的意思,希望对路过的有所帮助,更希望路过的能帮我检查检查. start: 首先,通过一个例子来说明,实践是检验真理的唯一标准. 结果:点击按钮,show=false时,div消失:再次点击,show=true,div用蓝色逐渐

  • 关于vue.js中this.$emit的理解使用

    目录 一.每个 Vue 实例都实现了事件接口 二.注意事项 三.例子及说明 四.总说明 一.每个 Vue 实例都实现了事件接口 即: 1.使用 $on(eventName) 监听事件 2.使用 $emit(eventName, optionalPayload) 触发事件 二.注意事项 1.父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件 2.不能用 $on 监听子组件释放的事件,而必须在模板里直接用 v-on 绑定 三.例子及说明 1.父组件代码及说明 <template>

  • 谈谈因Vue.js引发关于getter和setter的思考

    起因 当我打印出Vue实例下的data对象里的属性时,发现了一个有趣的事情: 它的每个属性都有两个相对应的get和set方法,我觉的这是多此一举的,于是去网上查了查Vue双向绑定的实现原理,才发现它和Angular.js双向绑定的实现原理完全不同,Angular是用的数据脏检测,当Model发生变化,会检测所有视图是否绑定了相关数据,再更改视图.而Vue使用的发布订阅模式,是点对点的绑定数据. Vue的数据绑定只有两个步骤,compile=>link. 我一直在想,vue是通过什么去监听用户对M

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

    一.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 最后会渲

  • 深入对Vue.js $watch方法的理解

    博主最近对着vue.js的官方教程在自学vue.js,博主自幼愚钝,在教程中真的是好多点都不太理解,接下来要说的这个$watch方法就是其中一个不太理解的点了.咱们先来看一下对于$watch方法在vue.js的API中是怎么解释的吧:观察 Vue 实例变化的一个表达式或计算属性函数.回调函数得到的参数为新值和旧值.表达式只接受监督的键路径.对于更复杂的表达式,用一个函数取代.官方示例: // 键路径 vm.$watch('a.b.c', function (newVal, oldVal) { /

  • 深入理解Vue.js源码之事件机制

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/answershuto/learnVue. 在学习过程中,为Vue加上了中文的注释https://github.com/answershuto/learnVue/tree/master/vue-src,希望可以对其他想学习Vue源码的小伙伴有所帮助. 可能会有理解存在偏差的地方,欢迎提issue指出

  • 深入理解Vue.js轻量高效的前端组件化方案

    Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue.js做一个深入的介绍. Vue.js 是我在2014年2月开源的一个前端开发库,通过简洁的 API 提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在 GitHub上已经有5000+的star.本文将从各方面对Vue.js做一个深入的介绍. 开发初衷

  • 对vue.js中this.$emit的深入理解

    对于vue.js中的this.emit的理解:this.emit('increment1',"这个位子是可以加参数的"):其实它的作用就是触发自定义函数. 看例子: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <script src="vue.js"

  • 深入理解vue.js中的v-if和v-show

    本文主要给大家介绍了关于vue.js中v-if和v-show的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 1.共同点 都是动态显示DOM元素 2.区别 (1)手段:v-if是动态的向DOM树内添加或者删除DOM元素:v-show是通过设置DOM元素的display样式属性控制显隐: (2)编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件:v-show只是简单的基于css切换: (3)编译条件:v-if是惰性的,如果初始条件为假,

  • 深入理解vue.js中$watch的oldvalue与newValue

    $watch中的oldvalue和newValue 大家都知道,在vue.js中给我们提供了$watch的方法来做对象变化的监听,而且在callback中会返回两个对象,分别是oldValue和newValue. 顾名思义,这两个对象就是对象发生变化前后的值. 但是在使用过程中我发现这两个值并不总是预期的.下面来一起看看详细的介绍: 定义data的值 data: { arr: [{ name: '笨笨', address: '上海' }, { name: '笨笨熊', address: '北京'

随机推荐