读深入浅出vue后感及抄录笔记。

第1章 遇见Vue.js

1.1 MVX模式是什么

MVC框架最早出现在Jaca领域,然后慢慢在前端开发中也被提到,后来又出现了MVP,以及现在最成熟的MVVM,下面我们来简单介绍一下各种模式。

1.1.1 MVC

MVC是应用最广泛的软件架构之一,一般MVC分为:Model(模型)、Controller(控制器)和View(视图)。这主要是基于分层的目的,让彼此的职责分开,如图1-1所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9fOC9zPu-1593097988626)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00003.jpg)]

图1-1 MVC通信方式一

View一般都是通过Controller来和Model进行联系的。Controller是Model和View的协调者,View和Model不直接联系。基本联系都是单向的。

那么,用户操作应该放在什么位置,MVC之间又会有什么变化,如图1-2所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RkBhTslK-1593097988629)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00004.jpg)]

图1-2 MVC通信方式二

用户(User)通过Controller来操作Model以达到View的变化。

1.1.2 MVP

MVP是从经典的MVC模式演变而来的,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

在MVP中,Presenter完全把View和Model进行了分离,主要的程序逻辑在Presenter里实现。而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View的时候可以保持Presenter不变。MVP通信方式如图1-3所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HB2LxxIm-1593097988633)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00005.jpg)]

图1-3 MVP通信方式

1.1.3 MVVM

MVVM代表框架有:知名度相对偏低的Knockout、早期的Ember.js、目前比较火热的来自Google的AngularJS,以及我们今天要讲的Vue.js。

相比前面两种模式,MVVM只是把MVC的Controller和MVP的Presenter改成了ViewModel。View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示。

这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作,如图1-4所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TK6XUPmO-1593097988637)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00006.jpg)]

图1-4 用户操作影响

第2章 数据绑定

数据绑定是将数据和视图相关联,当数据发生变化时,可以自动更新视图。本章将介绍Vue.js中数据绑定的语法。

2.1 语法

2.1.1 插值

文本插值是最基本的形式,使用双大括号{{ }}(类似于Mustache,所以本文中称作Mustache标签),代码示例如下:

<span>Text: {{text}}</span>

例子中的标签{{text}}将会被相应的数据对象text属性的值替换掉,当text的值改变时,文本中的值也会联动地发生变化。有时候只需渲染一次数据,后续数据变化不再关心,可以通过“*”实现,代码示例如下:

<span>Text: {{*text}} </span>

双大括号标签会把里面的值全部当作字符串来处理,如果值是HTML片段,则可以使用三个大括号来绑定,代码示例如下:

<div>Logo: {{{logo}}}</div>
logo : '<span>DDFE</span>'

双大括号标签还可以放在HTML标签内,示例如下:

<li data-id='{{id}}'></li>

总之,Vue.js提供了一系列文本渲染方式,足够我们应对日常的模板渲染情况。需要注意的是,Vue指令和自身特性内是不可以插值的,如果用错了地方,Vue.js会发出警告。

2.1.2 表达式

Mustache标签也接受表达式形式的值,表达式可由JavaScript表达式和过滤器构成。过滤器可以没有,也可以有多个。

表达式是各种数值、变量、运算符的综合体。简单的表达式可以是常量或者变量名称。表达式的值是其运算结果,代码示例如下:

<!--JS表达式 -->
{{ cents/100 }}   // 在原值的基础上除以100
{{ true? 1 : 0 }}  // 值为真,则渲染出1,否则渲染出0
{{ example.split(",") }}

<!--无效示例-->
{{var logo = 'DDFE'}}  // 这是语句,不是表达式
{{if(true) return 'DDFE'}}  // 条件控制语句是不支持的,可以使用三元式

类似于Linux中的管道,Vue.js允许在表达式后面添加过滤符,代码示例如下:

{{example | toUpperCase}}

这里toUpperCase就是过滤器,其本质是一个JS函数,返回字符串的全大写形式。Vue.js允许过滤器串联,代码示例如下:

{{example | filterA | filterB}}

过滤器还支持传入参数,代码示例如下:

{{example | filter a b}}

这里a和b均为参数、用空格隔开。

Vue.js还提供了许多内置的过滤器,第6章将对此进行详细介绍。

2.1.3 指令

指令是带有v-前缀的特殊特性,其值限定为绑定表达式,也就是JavaScript表达式和过滤器。指令的作用是当表达式的值发生变化时,将这个变化也反映到DOM上。代码示例如下:

<div v-if="show">DDFE</div>

当show为true时,展示DDFE字样,否则不展示。还有一些指令的语法稍有不同,在指令和表达式之间插入一个参数,用冒号分隔,如v-bind指令。代码示例如下:

<a v-bind:href="url"></a>
<div v-bind:click="action"></div>

2.2 分隔符

Vue.js中数据绑定的语法被设计为可配置的。如果不习惯Mustache风格的语法,则可以自己设置。

我们可以在Vue.config中配置绑定的语法。Vue.config是一个对象,包含了Vue.js的所有全局配置,可以在Vue实例化前修改其中的属性。分隔符在Vue.config中源码定义如下:

<!--源码目录src/config.js-->
let delimiters = ['{{', '}}']
let unsafeDelimiters = ['{{{', '}}}']

1.delimiters

Vue.config.delimiters = ["<%" ,"%>"]

如果修改了默认的文本插值的分隔符,则文本插值的语法由{{example}}变为<%example%>。

2.unsafeDelimiters

Vue.config.unsafeDelimiters = ["<$", "$>"]

如果修改了默认的HTML插值的分隔符,则HTML插值的语法由{{{example}}}变为< e m a m p l e emample emample>。

第3章 指令

指令(Directive)是特殊的带有前缀v-的特性。指令的值限定为绑定表达式,指令的职责就是当其表达式的值改变时把某些特殊的行为应用到DOM上。

3.1 内部指令

首先来看看和原生HTML标签相似的一组内置指令,这组指令非常容易记忆,因为仅仅是在原生标签前面加上了v-前缀,如图3-1所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vhAz0FK-1593097988642)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00007.jpg)]

图3-1 内部指令

3.1.1 v-if

v-if指令可以完全根据表达式的值在DOM中生成或移除一个元素。如果v-if表达式赋值为false,那么对应的元素就会从DOM中移除;否则,对应元素的一个克隆将被重新插入DOM中。代码示例如下:

<body class="native">
  <div id="example">
    <p v-if=greeting”>Hello</p>
  </div>
</body>
<script>
var exampleVM2 = new Vue({
  el: '#example',
  data: {
    greeting: false
  }
})
</script>

效果如图3-2所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVFTRfXj-1593097988646)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00008.jpg)]

图3-2 v-if

因为v-if是一个指令,需要将它添加到一个元素上。但是如果想切换多个元素,则可以把元素当作包装元素,并在其上使用v-if,最终的渲染结果不会包含它。代码示例如下:

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

效果如图3-3所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dIqc5ZHv-1593097988650)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00009.jpg)]

图3-3 v-if

3.1.2 v-show

v-show指令是根据表达式的值来显示或者隐藏HTML元素。当v-show赋值为false时,元素将被隐藏。查看DOM时,会发现元素上多了一个内联样式style=“display: none”。代码示例如下:

<body>
  <input type="text" v-model="message" placeholder="edit me"><body class="native">
  <div id="example">
    <p v-show="greeting">Hello!</p>
  </div>
</body>
<script>
  var exampleVM2 = new Vue({
    el: '#example',
    data: {
      greeting: false
    }
  })
</script>

效果如图3-4所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDZo5oRi-1593097988653)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00010.jpg)]

图3-4 v-show

注: v-show不支持语法。

在切换v-if模块时,Vue.js有一个局部编译/卸载过程,因为v-if中的模板可能包括数据绑定或子组件。v-if是真实的条件渲染,因为它会确保条件块在切换时合适地销毁与重建条件块内的事件监听器和子组件。

v-if是惰性的——如果初始渲染时条件为假,则什么也不做,在条件第一次变为真时才开始局部编译(编译会被缓存起来)。

相比之下,v-show简单得多——元素始终被编译并保留,只是简单地基于CSS切换。

一般来说,v-if有更高的切换消耗,而v-show有更高的初始渲染消耗。因此,如果需要频繁地切换,则使用v-show较好;如果在运行时条件不大可能改变,则使用v-if较好。

3.1.3 v-else

顾名思义,v-else 就是JavaScript中else的意思,它必须跟着v-if或v-show,充当else功能。代码示例如下:

<body class="native">
  <div id="example">
    <p v-if="ok">我是对的</p>
    <p v-else="ok">我是错的</p>
  </div>
</body>
<script>
  var exampleVM2 = new Vue({
    el: '#example',
    data: {
      ok: false
    }
  })
</script>

将v-show用在组件上时,因为指令的优先级v-else会出现问题,所以不要这样做。代码示例如下:

<custom-component v-show="condition"></custom-component>
<p v-else>这可能也是一个组件</p>

我们可以用另一个v-show替换v-else,代码示例如下:

<custom-component v-show="condition"></custom-component>
<p v-show="!condition">这可能也是一个组件</p>

3.1.4 v-model

v-model指令用来在input、select、text、checkbox、radio等表单控件元素上创建双向数据绑定。根据控件类型v-model自动选取正确的方法更新元素。尽管有点神奇,但是v-model不过是语法糖,在用户输入事件中更新数据,以及特别处理一些极端例子。代码示例如下:

<body id="example">
  <form>
    姓名:
    <input type="text" v-model="data.name" placeholder="">
    </br/>
    性别:
    <input type="radio" id="one" value="One" v-model="data.sex">
    <label for="man">男</label>
    <input type="radio" id="two" value="Two" v-model="data.sex">
    <label for="male">女</label>
    </br/>
    兴趣:
    <input type="checkbox" id="jack" value="book" v-model="data.interest">
    <label for="jack">阅读</label>
    <input type="checkbox" id="john" value="swim" v-model="data.interest">
    <label for="john">游泳</label>
    <input type="checkbox" id="mike" value="game" v-model="data.interest">
    <label for="mike">游戏</label>
    <input type="checkbox" id="mike" value="song" v-model="data.interest">
    <label for="mike">唱歌</label>
    <br>
    身份:
    <select v-model="data.identity">
      <option value="teacher" selected>教师</option>
      <option value="doctor" >医生</option>
      <option value="lawyer" >律师</option>
    </select>
  </form>
</body>
<script>
  new Vue({
    el: '#example',
    data: {
      data:{
        name:"",
        sex:"",
        interest:[],
        identity:''
      }
    }
   })
</script>

效果如图3-5所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8c3ATAXd-1593097988656)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00011.jpg)]

图3-5 v-model

除了以上用法,在v-model指令后面还可以添加多个参数(number、lazy、debounce)。

1.number

如果想将用户的输入自动转换为Number类型(如果原值的转换结果为NaN,则返回原值),则可以添加一个number特性。

2.lazy

在默认情况下,v-model在input事件中同步输入框的值与数据,我们可以添加一个lazy特性,从而将数据改到在change事件中发生。代码示例如下:

<body id="example">
  <input v-model="msg" lazy><br/>
  {{msg}}
</body>
<script>
  var exampleVM2 = new Vue({
    el: '#example',
    data: {
      msg: '内容是在change事件后才改变的~'
    }
  })
</script>

我们在input输入框中输入“依然没变”,虽然触发了input事件,但是因为加入了lazy属性,msg的值一直没有发生变化。效果如图3-6所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZTXmUGSh-1593097988661)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00012.jpg)]

图3-6 lazy

3.debounce

设置一个最小的延时,在每次敲击之后延时同步输入框的值与数据。如果每次更新都要进行高耗操作(例如,在input中输入内容时要随时发送AJAX请求),那么它较为有用。代码示例如下:

<body id="example">
  <input v-model="msg" debounce="5000"><br/>
  {{msg}}
</body>
<script>
  var exampleVM2 = new Vue({
    el: '#example',
    data: {
      msg: '内容是在5000ms后才改变的~'
    }
  })
</script>

在5000ms内我们将输入框的内容清空,msg的值没有马上改变,还依然保持着“内容是在5000ms后才改变的~”,效果如图3-7所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mE458xh6-1593097988666)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00013.jpg)]

图3-7 5000ms内效果

5000ms后内容才被清空,效果如图3-8所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sBc9yHj-1593097988673)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00014.jpg)]

图3-8 5000ms后效果

指令太多,详情见官网 https://vuejs.org/

第4章 计算属性

通常我们会在模板中绑定表达式,模板是用来描述视图结构的。如果模板中的表达式存在过多的逻辑,模板会变得臃肿不堪,维护变得非常困难。因此,为了简化逻辑,当某个属性的值依赖于其他属性的值时,我们可以使用计算属性。

4.1 什么是计算属性

计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的DOM部分也会同步自动更新。代码示例如下:

<div id="example">
  <input type="text" v-model="didi" />
  <input type="text" v-model="family" />
  <br>
  didi={{ didi }}, family={{ family }}, didiFamily = {{ didiFamily }}
</div>
var vm = new Vue({
  el: '#example',
  data: {
    didi: 'didi',
    family: 'family'
  },
  computed: {
    // 一个计算属性的getter
    didiFamily: function () {
      // `this` 指向 vm 实例
      return this.didi + this.family
    }
  }
})

当vm.didi和vm.family的值发生变化时,vm.didiFamily的值会自动更新,并且会自动同步更新DOM部分。

前面实例只提供了getter,实际上除了getter,我们还可以设置计算属性的setter。代码示例如下:

var vm = new Vue({
  el: '#example',
  data: {
    didi: 'didi',
    family: 'family'
  },
  computed: {
    didiFamily: {
      // 一个计算属性的 getter
      get: function () {
        // `this` 指向 vm 实例
        return this.didi + ' ' + this.family
      },
      // 一个计算属性的 setter
      set: function (newVal) {
        var names = newVal.split(' ')
        this.didi = names[0]
        this.family = names[1]
      }
    }
  }
})

当设置vm.didiFamily的值时,vm.didi和vm.family的值也会自动更新。

4.2 计算属性缓存

计算属性的特性的确很诱人,但是如果在计算属性方法中执行大量的耗时操作,则可能会带来一些性能问题。例如,在计算属性getter中循环一个大的数组以执行很多操作,那么当频繁调用该计算属性时,就会导致大量不必要的运算。

在Vue.js 0.12.8版本之前,只要读取相应的计算属性,对应的getter就会重新执行。而在Vue.js 0.12.8版本中,在这方面进行了优化,即只有计算属性依赖的属性值发生了改变时才会重新执行getter。

这样也存在一个问题,就是只有Vue实例中被观察的数据属性发生了改变时才会重新执行getter。但是有时候计算属性依赖实时的非观察数据属性。代码示例如下:

var vm = new Vue({
  data: {
    welcome: 'welcome to join didiFamily'
  },
  computed: {
    example: function () {
      return Date.now() + this.welcome
    }
  }
})

我们需要在每次访问example时都取得最新的时间而不是缓存的时间。从Vue.js 0.12.11版本开始,默认提供了缓存开关,在计算属性对象中指定cache字段来控制是否开启缓存。代码示例如下:

var vm = new Vue({
  data: {
    welcome: 'welcome to join didifamily'
  },
  computed: {
    example: {
      // 关闭缓存,默认为true
      cache: false, 
      get: function () {
        return Date.now() + this.welcome
      }
    }
  }
})

设置cache为false关闭缓存之后,每次直接访问vm.example时都会重新执行getter方法。

4.3 常见问题

在实际开发中使用计算属性时,我们会遇到各种各样的问题,以下是我们搜集到的一些常见问题以及解决方案。

4.3.1 计算属性getter不执行的场景

从前面章节中我们了解到,当计算属性依赖的数据属性发生改变时,计算属性的getter方法就会执行。但是在有些情况下,虽然依赖数据属性发生了改变,但计算属性的getter方法并不会执行。

当包含计算属性的节点被移除并且模板中其他地方没有再引用该属性时,那么对应的计算属性的getter方法不会执行。代码示例如下:

<div id="example">
  <button @click='toggleShow'>Toggle Show Total Price</button>
  <p v-if="showTotal">Total Price = {{totalPrice}}</p>
</div>
new Vue({
  el: '#example',
  data: {
    showTotal: true,
    basePrice: 100
  },
  computed: {
    totalPrice: function () {
      return this.basePrice + 1
    }
  },
  methods: {
    click: function() {
      this.showTotal = !this.showTotal
    }
  }
})

当点击按钮使showTotal为false时,此时P元素会被移除,在P元素内部的计算属性totalPrice的getter方法不会执行。但是当计算属性一直出现在模板中时,getter方法还是会被执行。代码示例如下:

<div id="example">
  <button @click='toggleShow'>Toggle Show Total Price</button>
  <!-- 一直出现在模板中,不会条件性隐藏 -->
  <p>{{totalPrice}}</p>
  <p v-if="showTotal">Total Price = {{totalPrice}}</p>
</div>

4.3.2 在v-repeat中使用计算属性

有时候从后端获得JSON数据集合后,我们需要对单条数据应用计算属性。在Vue.js 0.12之前的版本中,我们可以在v-repeat所在元素上使用v-component指令。代码示例如下:

<div id="items">
  <p v-repeat="items" v-component="item">
    <button>{{fulltext}}</button>
  </p>
</div>
var items = [
  { number:1, text:'one' },
  { number:2, text:'two' }
]
var vue = new Vue({
  el: '#items',
  data: { items: items },
  components: {
    item: {
      computed: {
        fulltext: function() {
          return 'item ' + this.text
        }
      }
    }
  }
})

在Vue.js 0.12.*版本中,Vue.js废弃了v-component指令,所以我们需要使用自定义元素组件来实现在v-repeat中使用计算属性。代码示例如下:

<div id="items">
  <my-item v-repeat="items" inline-template>
    <button>{{fulltext}}</button>
  </my-item>
</div>
var items = [
  { number:1, text:'one' },
  { number:2, text:'two' }
]
var vue = new Vue({
  el: '#items',
  data: { items: items },
  components: {
    'my-item': {
      replace: true,
      computed: {
        fulltext: function() {
          return 'item ' + this.text
        }
      }
    }
  }
})

第5章 表单控件绑定

在Web应用中,我们经常会使用表单向服务端提交一些数据,而通常也会在表单项中绑定一些如input、change等事件对用户输入的数据进行校验、更新等操作。在Vue.js中、我们可以使用v-model指令同步用户输入的数据到Vue实例data属性中,同时会对radio、checkbox、select等原生表单组件提供一些语法糖使表单操作更加容易。

5.1 基本用法

下面我们列举基本例子来看看如何使用v-model更新表单控件,具体的v-model数据绑定会在后续章节中展开介绍。

5.1.1 text

设置文本框v-model为name,代码示例如下:

<span>Welcome {{ name }} join DDFE</span>
<br>
<input type="text" v-model="name" placeholder="join DDFE">

当用户操作文本框时,vm.name会自动更新为用户输入的值,同时,span内的内容也会随之改变。

等等。。。。。

5.2 值绑定

在通常情况下,对于radio、checkbox、select组件,通过v-model绑定的值都是字符串,checkbox除外,checkbox可能是布尔值。代码示例如下:

<!-- 勾选时 `picked` 的值是字符串 a -->
<input type="radio" v-model="picked" value="a">
<!-- 勾选时 `toggle` 的值是布尔值 true,否则是布尔值 false -->
<input type="checkbox" v-model="toggle">
<!-- 勾选时 `selected` 的值是字符串 abc-->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

5.3 v-model修饰指令

v-model用来在视图与Model之间同步数据,但是有时候我们需要控制同步发生的时机,或者在数据同步到Model之前将数据转换为Number类型。我们可以在v-model指令所在的form控件上添加相应的修饰指令来实现这个需求。

5.3.1 lazy

在默认情况下,v-model在input事件中同步输入框的值与数据,可以添加一个lazy特性,从而改到在change事件中去同步。代码示例如下:

<input v-model="msg" lazy><br/>
{{msg}}

第6章 过滤器

在了解过滤器之前,我们需要明确一个概念——过滤器,本质上都是函数。其作用在于用户输入数据后,它能够进行处理,并返回一个数据结果。Vue.js与AngularJS中的过滤器语法有些相似,使用管道符(|)进行连接。代码示例如下:

{{'abc' | uppercase}}
//'abc' => 'ABC'

这里使用了Vue.js内置的过滤器uppercase,将字符串中的字母全部转换为大写形式。

6.1 内置过滤器

Vue.js内置了一系列常用的过滤器,可以直接进行调用。这些内置过滤器都相对比较简单,如果要实现比较复杂或者需要定制的过滤功能,还是要借助自定义过滤器的方式。当然,这些内置的过滤器使用时无须定义,比较适合刚上手Vue.js的新人。我们来看一下Vue.js中常用的过滤器,如图6-1所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCTjqO9V-1593097988676)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00037.jpg)]

图6-1 Vue.js内置的常用过滤器

6.1.1 字母操作

Vue.js内置了capitalize、uppercase、lowercase三个过滤器用于处理英文字符。注:这三个过滤器仅针对英文字符串使用。

1.capitalize

capitalize过滤器用于将表达式中的首字母转换为大写形式。代码示例如下:

{{ 'ddfe' | capitalize }}
//'ddfe' => 'Ddfe'

6.2 自定义过滤器

大多数情况下,Vue.js中内置的过滤器并不能满足我们的需求,好在Vue.js还提供了自定义过滤器的API供用户进行功能扩展。在学习Vue.js自定义过滤器之前,我们先来看看如何在AngularJS中自定义过滤器。代码示例如下:

angular.module('dd.filters', [])
    .filter('reverse', function (value) {
         return value.split('').reverse().join('')
})

<p>{{ msg | capitalize | reverse: '123' }}</p>
<!--此处 reverse 过滤器带的参数'123'并不起作用,只是用于展示AngularJS的过滤器接受参数的书写形式 -->

Vue.js中自定义过滤器的语法与AngularJS在形式上相近,但是语法略有不同。

6.2.1 fillter语法

在Vue.js中也存在一个全局函数Vue.filter用于构造过滤器:

Vue.filter(ID,function(){})

该函数接受两个参数,其中第一个参数为过滤器ID,作为用户自定义过滤器的唯一标识;第二个参数则为具体的过滤器函数。过滤器函数以值为参数,返回转换后的值。

1.单个参数

注册一个名为reverse的过滤器,作用是将字符串反转输出。代码示例如下:

Vue.filter('reverse', function (value) {
  return value.split('').reverse().join('');
})

<span v-text="message | reverse"></span>
<!-- 'abc' => 'cba' -->

2.多参数

过滤器函数除了以值为参数外,还支持接受任意数量的参数,参数之间以空格分隔。代码示例如下:

Vue.filter('wrap', function (value, begin, end) {
  return begin + value + end
})

<span v-text="message | wrap 'before' 'after'"></span>
<!-- 'hello' => 'before hello after' -->

3.双向过滤器

上面的过滤器函数都是在Model数据输出到View层之前进行数据转化的,实际上Vue.js还支持把来自视图(input元素)的值在写回模型前进行转化,即双向过滤器。代码示例如下:

Vue.filter(id, {
    // model -> view
    // read 函数可选
    read: function(val){},
    
    // view -> model
    // write函数将在数据被写入 Model 之前调用
    // 两个参数分别为表达式的新值和旧值
    write: function(newVal, oldVal){}
});

4.动态参数

filter语法还有一个需要注意的点:动态参数。如果过滤器参数没有用引号包起来,则它会在当前vm作用域内动态计算。此外,过滤器函数的this始终指向调用它的vm。代码示例如下:

<input v-model="userInput">
<span>{{msg | concat userInput}}</span>

<!--此处过滤器接受的参数userInput根据用户输入动态计算-->
Vue.filter('concat', function (value, input) {
  // `input` === `this.userInput`
  return value + input
})

6.2.2 教你写一个filter

针对常规过滤器,6.2.1节中已经给出一个比较简单的过滤器reverse的实现,代码示例如下:

Vue.filter('reverse', function (value) {
  return value.split('').reverse().join('');
})

需要注意两点:

  • 需要给定过滤器一个唯一标识。如果用户自定义的过滤器和Vue.js内置的过滤器冲突,那么Vue.js内置的过滤器将会被覆盖;如果后注册的过滤器和之前的过滤器冲突,则之前注册的过滤器层被覆盖。

  • 过滤器函数的作用是输入表达式的值,经过处理后输出。因此,定义的函数最好可以返回有意义的值。函数没有return语句不会报错,但这样的过滤器没有意义。

    第7章 Class与Style绑定

    对于数据绑定,一个常见的需求是操作元素的class列表和它的内联样式。因为它们都是 attribute,我们可以用v-bind处理它们:只需要计算出表达式最终的字符串。不过,字符串拼接麻烦又易错。因此,在v-bind用于class和style时,Vue.js专门增强了它。表达式的结果类型除了字符串以外,还可以是对象或数组。

    7.1 绑定HTML Class

    7.1.1 对象语法

    我们可以传给v-bind:class一个对象,以动态地切换class。注意,v-bind:class指令可以与普通的class特性共存。代码示例如下:

    <div id='example' class="static" v-bind:class="{ 'didi-orange': isRipe, 'didi-green': isNotRipe }"></div>
    var vm = new Vue({
      el: 'example',
      data: {
        isRipe: true,
        isNotRipe: false
      }
    })
    

    渲染为:

    <div id='example' class="static didi-orange"></div>
    

    当isRipe和isNotRipe变化时,class列表将相应地更新。例如,如果isNotRipe变为true,那么class列表将变为"static didi-orange didi-green"。(当然,一般情况下,v-bind:class绑定的对象中只有一个class会生效,这取决于用户自己的设置。)

    注: 尽管可以用Mustache标签绑定class,比如class="{{ className }}",但是我们不推荐这种写法和v-bind:class混用。

    我们也可以直接绑定数据中的一个对象,代码示例如下:

    <div id='example' v-bind:class="ddfe"></div>
    var vm = new Vue({
      el: 'example',
      data: {
        ddfe: {
          'didi-orange': true,
          'didi-green': false
        }
      }
    })
    

    还可以在这里绑定一个返回对象的计算属性。这是一种常用且强大的模式。代码示例如下:

    <div id='example' v-bind:class="ddfe"></div>
    var vm = new Vue({
      el: 'example',
      data: {
        didiAge:4,
        didiMember:6000 
      }
      computed: {
        ddfe: function(){
          return {
            'didi-orange': this.didiAge>3 ? true: false,
            'didi-large': this.didiMember>1000 ? true: false
          }
        }
      }
    })
    

    7.1.2 数组语法

    我们可以把一个数组传给v-bind:class,以应用一个class列表。代码示例如下:

    <div id='example' v-bind:class="[didiHandsome, didiBeautiful]">
    var vm = new Vue({
      el: 'example',
      data: {
        didiHandsome: 'didi-handsome',
        didiBeautiful: 'didi-beautiful'
      }
    })
    

    渲染为:

    <div id='example' class="didi-handsome didi-beautiful"></div>
    

    如果想根据条件切换列表中的class,则可以用三元表达式。代码示例如下:

    <div id='example' v-bind:class="[didiHandsome, isRipe ? didiOrange: '']">
    

    此例始终添加didiHandsome,但是只有在isRipe为true时才会添加didiOrange。

    不过,当有多个条件class时这样写有些烦琐。在Vue.js 1.0.19及以后版本中,可以在数组语法中使用对象语法。代码示例如下:

    <div id='example' v-bind:class="[didiHandsome, { didiOrange: isRipe, didiGreen: isNotRipe }]">
    

7.2 绑定内联样式

7.2.1 对象语法

v-bind:style的对象语法十分直观——看着非常像CSS,其实它是一个JavaScript对象。CSS属性名可以用驼峰式(camelCase)或短横分隔命名(kebab-case)。代码示例如下:

<div id='example' v-bind:style="{ color: didiColor, fontSize: fontSize + 'px' }"></div>
var vm = new Vue({
  el: 'example',
  data: {
    didiColor: 'orange',
    fontSize: 30
  }
})

通常直接绑定到一个样式对象更好,让模板更清晰。代码示例如下:

<div id='example' v-bind:style="ddfe"></div>
var vm = new Vue({
  el: 'example',
  data: {
    ddfe: {
      color: orange,
      fontSize: '13px'
    }
  }
})

同样的,对象语法常常结合返回对象的计算属性使用。代码示例如下:

<div id='example' v-bind:style="ddfe"></div>
var vm = new Vue({
  el: 'example',
  data: {
  didiAge:4,
    didiMember:6000 
}
  computed: {
    ddfe: function(){
    return {
      color: this.didiAge>3 ? orange: green,
      fontSize: this.didiMember>1000 ? 20px: 10px
    }
    }
  }
})

7.2.2 数组语法

v-bind:style的数组语法可以将多个样式对象应用到一个元素上。代码示例如下:

<div v-bind:style="[ddfe, didiFamily]">

第8章 过渡

过渡效果在交互体验中的重要性不言而喻。以往我们使用jQuery添加或移除元素的类,搭配CSS中定义好的样式,再引用一些JavaScript库之后,可以做出非常复杂、惊艳的动态效果,不过这一套方法仍略显烦琐。Vue.js内置了一套过渡系统,可以在元素从DOM中插入或移除时自动应用过渡效果。Vue.js会在适当的时机触发CSS过渡或动画,用户也可以提供相应的JavaScript钩子函数在过渡过程中执行自定义DOM操作。

应用过渡效果,需要在目标元素上使用transition特性。代码示例如下:

<div v-if="show" transition="my-transition"></div>

transition特性可以与以下资源一起搭配使用:

  • v-if
  • v-show
  • v-for(只在插入和删除时触发,使用vue-animated-list插件)
  • 动态组件(见“组件”一章)
  • 在组件的根节点上,并且被Vue实例的DOM方法(如vm.$appendTo(el))触发

当插入或者删除带有transition特性的元素时,Vue.js将执行以下操作:

  • 尝试以ID“my-transition”查找JavaScript过渡钩子对象,该对象通过Vue.transition(id, hooks)或transitions选项注册(后文将介绍)。如果找到了,将在过渡的不同阶段调用相应的钩子。
  • 自动嗅探目标元素是否有CSS过渡或动画(按照Vue.js指定的方式添加类名即可),并在合适时添加/删除CSS类名,免去了用户自己进行相关操作的烦琐。
  • 如果没有找到JavaScript钩子并且也没有检测到CSS过渡/动画,DOM操作(插入/删除)将在下一帧中立即执行。

第9章 Method

Vue.js的事件监听一般都通过v-on指令配置在HTML中,虽然也可以在JavaScript代码中使用原生addEventListener方法添加事件监听,但Vue.js本身并不提倡如此。看上去这种方式不符合传统的“关注点分离”(separation of concern)的理念,但其实所有的Vue.js事件处理方法和表达式都严格绑定在当前视图的ViewModel上。实际上,采用它提供的v-on指令有如下几点好处:

  • 通过查看HTML模板便能轻松定位JavaScript代码中对应的方法。

  • 无须在JavaScript中手动绑定事件,ViewModel和DOM完全解耦,更易于测试。

  • 当一个ViewModel被销毁时,所有的事件处理器都会自动被删除。

  • 9.1.2 methods配置

    在上一节中,当用户将click事件与某个方法绑定时,需要在Vue实例当中进行定义,所有定义的方法都放在methods属性下。针对上一节的greet方法定义代码示例如下:

    var vm = new Vue({
      el: '#example',
      // 在 `methods` 对象中定义方法
      methods: {
        greet: function (event) {
          // 方法内 `this` 指向 vm
          alert('Welcome to Vue.js By DDFE!')
          // `event` 是原生 DOM 事件
          alert(event.target.tagName)
        }
      }
    })
    // 也可以在 JavaScript 代码中调用方法
    vm.greet()
    

    对于say方法,可按照如下方式定义:

    new Vue({
      el: '#example-2',
      methods: {
        say: function (msg) {
          alert(msg)
        }
      }
    })
    

    需要注意的地方如下:

    • methods中定义的方法内的this始终指向创建的Vue实例。

    • 与事件绑定的方法支持参数event即原生DOM事件的传入。

    • 方法用在普通元素上时,只能监听原生DOM事件;用在自定义元素组件上时,也可以监听子组件触发的自定义事件(详见“组件”一章)。

    • 第10章 Vue实例方法

      本章我们介绍Vue实例提供的一些有用的属性和方法,这些属性和方法名都以前缀$开头。

      10.1 实例属性

      在详细讲解每个属性的使用之前,我们先看一下属性总览图,如图10-1所示。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jq0TJUig-1593097988680)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00041.jpg)]

      图10-1 Vue实例属性总览

      10.1.1 组件树访问

      1.$parent

      用来访问当前组件实例的父实例。

      2.$root

      用来访问当前组件树的根实例,如果当前组件没有父实例,$root表示当前组件实例本身。

      3.$children

      用来访问当前组件实例的直接子组件实例。

      4.$refs

      用来访问使用了v-ref指令的子组件。v-ref的详细介绍请参阅3.1.11节。

      10.1.2 DOM访问

      1.$el

      用来访问挂载当前组件实例的DOM元素。

      2.$els

      用来访问$el元素中使用了v-el指令的DOM元素。v-el的详细介绍请参阅3.1.12节。

      10.1.3 数据访问

      1.$data

      用来访问组件实例观察的数据对象,该对象引用组件实例化时选项中的data属性。

      2.$options

      用来访问组件实例化时的初始化选项对象。

      10.2 实例方法

      10.2.1 实例DOM方法的使用

      在详细讲解每个方法的使用之前,我们先看一下方法总览图,如图10-2所示。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8XqTEuap-1593097988681)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00042.jpg)]

      图10-2 Vue实例DOM方法总览

      1.$appendTo()

      $appendTo()方法用来将el所指的DOM元素或片段插入到目标元素中。

      该方法接受两个参数:

      • elementOrSelector(字符串或DOM元素),该参数可以是一个选择器字符串或者DOM元素。
      • callback(可选,函数),回调函数,该回调函数会在el元素被插入到目标元素后被触发。注:如果在el上应用了过渡效果,则回调会在过渡完成后被触发。

      2.$before()

      $before()方法用来将el所指的DOM元素或片段插入到目标元素之前。

      该方法接受两个参数:

      • elementOrSelector(字符串或DOM元素),该参数可以是一个选择器字符串或者DOM元素。
      • callback(可选,函数),回调函数,该回调函数会在el元素被插入到目标元素后被触发。注:如果在el上应用了过渡效果,则回调会在过渡完成后被触发。

      3.$after()

      $after()方法用来将el所指的DOM元素或片段插入到目标元素之后。

      该方法接受两个参数:

      • elementOrSelector(字符串或DOM元素),该参数可以是一个选择器字符串或者DOM元素。
      • callback(可选,函数),回调函数,该回调函数会在el元素被插入到目标元素后被触发。注:如果在el上应用了过渡效果,则回调会在过渡完成后被触发。

      4.$remove()

      $remove()方法用来将el所指的DOM元素或片段从DOM中删除。

      该方法接受一个参数:

      • callback(可选,函数),回调函数,该回调函数会在el元素在DOM中被删除后触发。

      注:如果在el上应用了过渡效果,则回调会在过渡完成后被触发。

      5.$nextTick()

      $nextTick()方法用来在下次DOM更新循环后执行指定的回调函数,使用该方法可以保证DOM中的内容已经与最新数据保持同步。

      该方法接受一个参数:

      • callback(可选,函数),回调函数,该回调函数会在下次DOM更新循环后被执行。它和全局的Vue.nextTick方法一样,不同的是,callback中的this会自动绑定到调用它的Vue实例上。

      10.2.2 实例Event方法的使用

      在详细讲解每个方法的使用之前,我们先看一下Vue实例事件总览图,如图10-3所示。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DpjWpsgJ-1593097988683)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00043.jpg)]

      图10-3 Vue实例事件总览

      1.$on()

      $on()方法用来监听实例上的自定义事件。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • callback(函数),回调函数,该回调函数会在执行 e m i t 、 emit、 emitbroadcast或者$dispatch后触发。

      2.$once()

      $once()方法也是用来监听实例上的自定义事件,但只触发一次。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • callback(函数),回调函数,该回调函数会在执行 e m i t 、 emit、 emitbroadcast或者$dispatch后触发。

      3.$emit()

      $emit()方法用来触发事件。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • args(可选),传递给监听函数的参数。

      4.$dispatch()

      $dispatch()方法用来派发事件,即先在当前实例触发,再沿着父链一层一层向上,如果对应的监听函数返回false就停止。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • args(可选),传递给监听函数的参数。

      5.$broadcast()

      b r o a d c a s e ( ) 方 法 用 来 广 播 事 件 , 即 遍 历 当 前 实 例 的 broadcase()方法用来广播事件,即遍历当前实例的 broadcase()广children,如果对应的监听函数返回false就停止。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • args(可选),传递给监听器的参数。

      6.$off()

      $off()方法用来删除事件监听器。

      该方法接受两个参数:

      • event(字符串),该参数可以是一个事件名称。
      • callback(可选,函数),对应的回调函数。

      如果没有参数,即删除所有的事件监听器;如果只提供一个参数——事件名称,即删除它对应的所有监听器;如果提供两个参数——事件名称和回调函数,即删除对应的这个回调函数。

      第11章 组件

      组件是Vue.js最推崇的,也是最强大的功能之一,核心目标是为了可重用性高,减少重复性的开发。我们可以把组件代码按照template、style、script的拆分方式,放置到对应的.vue文件中。

      Vue.js的组件可以理解为预先定义好行为的ViewModel类。一个组件可以预定义很多选项,但最核心的是以下几个:

      • 模板(template)—— 模板声明了数据和最终展现给用户的DOM之间的映射关系。

      • 初始数据(data)—— 一个组件的初始数据状态。对于可复用的组件来说,通常是私有的状态。

      • 接受的外部参数(props)—— 组件之间通过参数来进行数据的传递和共享。参数默认是单向绑定(由上至下),但也可以显式声明为双向绑定。

      • 方法(methods)—— 对数据的改动操作一般都在组件的方法内进行。可以通过v-on指令将用户输入事件和组件方法进行绑定。

      • 生命周期钩子函数(lifecycle hooks)—— 一个组件会触发多个生命周期钩子函数,比如created、attached、destroyed等。在这些钩子函数中,我们可以封装一些自定义的逻辑。和传统的MVC相比,这可以理解为Controller的逻辑被分散到了这些钩子函数中。

      • 11.3 生命周期

        在Vue.js中,在实例化Vue之前,它们以HTML的文本形式保存在文本编辑器中。当实例化后将经历创建、编译和销毁三个主要阶段,如图11-9所示。

        生命周期钩子:

        1.init

        在实例开始初始化时同步调用。此时数据观测、事件和Watcher都尚未初始化。

        2.created

        在实例创建之后同步调用。此时实例已经结束解析选项,这意味着已建立:数据绑定、计算属性、方法、Watcher/事件回调。但是还没有开始DOM编译,$el还不存在。

        3.beforeCompile

        在编译开始前调用。

        4.compiled

        在编译结束后调用。此时所有的指令已生效,因而数据的变化将触发DOM更新。但是不担保 $el 已插入文档。

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HP9u62r5-1593097988687)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00052.jpg)]

第13章 与服务端通信

弃用。。。

第14章 路由与视图

同AngularJS一样,Vue.js也很适合用来做大型单页应用。Vue.js本身并没有提供路由机制,但是官方以插件(vue-router)的形式提供了对路由的支持。vue-router 0.7.13支持嵌套路由、组件惰性载入、视图切换动画、具名路径等特性。以下内容讲解都是基于vue-router 0.7.13版本,后面就不加版本号了。

第15章 vue-cli

使用Vue.js开发大型应用时,我们需要考虑代码目录结构、项目构建和部署、热加载、代码单元测试等事情。如果每个项目都要手动完成这些工作,那无疑效率是低下的,所以通常我们会使用一些脚手架工具来帮助完成这些事情。在Vue.js生态中我们可以使用vue-cli脚手架工具来快速构建项目。

第16章 测试开发与调试

任何实际项目的开发都不仅仅是完成编码,规范的开发流程和严谨的测试都是不可或缺的。合理使用各种工具来进行测试开发与调试,能够极大地提升编写代码的效率,使开发过程事半功倍、对于提高代码质量、稳定线上服务至关重要。

Vue.js除了是一个前端类库之外,还开发了许多配合使用的工具。比如Chrome下的调试工具、编辑器下的高亮工具等。正是这样一个完整的生态环境,使得用Vue.js开发变得更加简便。本章将为大家介绍几个常用的配合Vue.js使用的工具。

16.1 测试工具

16.1.1 ESLint

在日常的团队开发中,为了避免出现低级bug和统一代码风格,通常会在开发前约定一套编码规范。为了保证规范的执行,可以使用Lint工具和代码风格检测工具。

ESLint就是一个Lint工具,它是由JS红宝书的作者 Nicholas C.Zakas创立的一个开源项目,旨在为大家提供一个可扩展、每条规则独立、不内置编码风格的语法检查工具。ESLint有别于JSLint的地方就是它被设计成完全可配置的,每一条规则都是一个插件,用户完全可以根据自己的需求来选择使用哪些规则。比如报错就可以设计为“警告”和“错误”两个等级,或者禁用。

下面介绍一下ESLint的配置。

在项目中配置ESLint有两种基本方法:

  • 用JavaScript注解的方式将配置信息直接加到文件里。
  • 使用JavaScript、JSON或YAML文件为整个目录定义配置信息。文件格式可以是.eslintrc.*或package.json。ESLint会自动查找并读取配置文件。

需要配置的有以下几块信息,所有这些配置都将细粒度地决定ESLint如何检测代码。这里以JSON格式为例,展示一下基本的配置规则。

1.Enviroments

脚本将要运行的环境,每个环境都有自己预定义好的全局变量集合。通过env关键字配置Environments选项,下面的配置表示脚本将运行在浏览器(browser)和node环境。还可以配置Commonjs、jQuery等很多选项。

<!-- package.json -->
{ 
  "env":{
    "browser": true,
    "node": true
  } 
}

2.Globals

在脚本运行期间需要额外加入的全局变量。当变量在当前文件中未定义却被访问时,会触发未定义规则警告。因此,如果设置了一些全局变量,则需要在ESLint的配置文件中进行配置。

<!-- package.json -->
{
  "globals":{
    "varA": true,
    "varB": false
  }
}

上述配置表明varA、varB 都是全局变量,其中varB的值不可写(只读)。

3.Rules

ESLint提供了大量的规则,用户通过配置规则是否生效来定义自己的项目需要使用哪些规则。

<!-- package.json -->
{
  "rules": {
    "eqeqe": "off",
    "curly": "error"
  }
}

17.6 总结

Vue.js的设计思想是专注而灵活,它只聚焦视图层,响应的数据绑定和组件系统是其特色。当我们采用Vue.js构建一些大型应用时,就不得不考虑Web前端工程化的一些事情了,而Scrat在工程化方面做得特别棒。Scrat和Vue.js在组件化开发思想上不谋而合,相得益彰,Scrat+Vue.js产生的化学反应是美妙的,它们必将成为开发大型项目的利器。

第18章 Vue.js 2.0

Vue.js 2.0 preview版本于2016年4月底发布,相对于1.x版本,Vue.js 2.0做了不少的改进和优化。除了部分API变更、模板更加灵活之外,最吸引人的恐怕就是高性能的Virtual DOM和流式服务端渲染功能了。接下来就让我们一起走进Vue.js 2.0的世界,看一看Vue.js 2.0给我们带来了哪些惊喜。

5.生命期钩子函数部分

在Vue.js 2.0中,Vue实例的生命周期发生了一些变化,如图18-1所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oChFPIO1-1593097988692)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00093.jpg)]

图18-1 Vue.js 2.0生命周期图示

  • 新增beforeMount

Vue.js 2.0新增了beforeMount钩子函数,它的调用时机是在模板编译成render方法之后、创建Watcher之前。

  • 新增mounted

Vue.js 2.0新增了mounted钩子函数,它的调用时机是在DOM树生成之后。

  • 新增beforeUpdate

Vue.js 2.0新增了beforeUpdate钩子函数,它的调用时机是在Virtual DOM生成之后、DOM树生成之前,调用条件是这个vm实例已经mounted过。

  • 新增update

Vue.js 2.0新增了update钩子函数,它的调用时机是在DOM树生成之后,调用条件是这个vm实例已经mounted过。

  • 新增activated

Vue.js 2.0新增了activated钩子函数,它的调用时机是在DOM树生成之后,调用条件是keep-alive组件。

  • 新增deactivated

Vue.js 2.0新增了deactivated钩子函数,它的调用时机是在Vue实例销毁时,调用条件是keep-alive组件。

  • 废弃ready

在Vue.js 1.x版本中,ready钩子函数的调用时机是第一次插入DOM后。Vue.js 2.0并不一定执行在浏览器环境中,也可能是在服务端渲染,因此废弃了该钩子函数并用mounted钩子函数替代。

  • 废弃beforeCompile

在Vue.js 1.x版本中,beforeCompile钩子函数的调用时机是在模板编译前。Vue.js 2.0废弃了该钩子函数并用created钩子函数替代。

  • 废弃compiled

在Vue.js 1.x版本中compiled钩子函数的调用时机是在编译模板之后、DOM创建之前。Vue.js 2.0废弃了该钩子函数并用mounted钩子函数替代。

  • 废弃attached

在Vue.js 1.x版本中attached钩子函数的调用时机是插入DOM时。Vue.js 2.0不一定会创建真实的DOM,因此废弃了该钩子。

  • 废弃detached

在Vue.js 1.x版本中,attached钩子函数的调用时机是移除DOM时,废弃理由同上。

第19章 源码篇——util

Vue.js内部封装了util,提供了一些常用的工具方法。了解本章内容,可以避免开发者再额外引用第三方框架增加代码量。util一共分成6部分:env、dom、components、lang、debug和options,整体结构如图19-1所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EupKW0KR-1593097988696)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00106.jpg)]

图19-1 util整体结构

第20章 源码篇——深入响应式原理

Vue.js最显著的功能就是响应式系统,它是一个典型的MVVM框架,模型(Model)只是普通的JavaScript对象,修改它则视图(View)会自动更新。这种设计让状态管理变得非常简单而直观,不过理解它的原理也很重要,可以避免一些常见问题。下面让我们深挖Vue.js响应式系统的细节,来看一看Vue.js是如何把模型和视图建立起关联关系的。

第21章 源码篇——父子类合并策略

相信在前面的组件篇中已经有同学看到了组件的mixin特性,里面也提到了两种合并策略。

当混合对象中出现下面两种情况时:

  • 混合对象和组件存在同名的生命周期方法时,它们都会合并到一个数组中,混合对象的生命周期方法优先执行,组件的同名生命周期方法后执行。

  • 混合对象的其他选项如methods中定义了和组件同名的方法时,组件会覆盖混合对象的同名方法。

  • 第22章 源码篇——缓存

    其实很多同学都看过Vue.js的源码,或者已经在前面的一些源码示例章节中看到了Cache,本节我们就来讲述它。

    比如在模板解析的源码中:

    <!--源码目录:src/parsers/template.js -->
    const templateCache = new Cache(1000)
    // stringToFragment方法中的应用
    var hit = templateCache.get(cacheKey)
    // stringToFragment方法中的应用
    templateCache.put(cacheKey, frag)
    

    22.1 Cache有什么用

    顾名思义,缓存一般可以用来放置一些数据,同时提供一些API来操作数据,如图22-1所示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zSc9jOnk-1593097988698)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00133.jpg)]

    图22-1 Cache对象

    第23章 源码篇——属性props

    其实很多同学都使用过props配置给组件元素设置一些属性,本章我们从源码角度来分析一下相关的具体实现。

    23.1 流程设计

    我们看一下初始化props的流程,如图23-1所示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-seAVeZyg-1593097988701)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00135.jpg)]

    图23-1 props初始化流程图

    第24章 源码篇——events

    前面我们介绍过通过methods对象配置来给模板DOM元素绑定事件,那么如何在Vue.js实例之间以及父子类之间通过事件来通信呢?我们可以通过events这个配置项来实现。

    24.1 events配置是什么

    其实可以理解为一个简单的配置对象:

    • Key是在实例事件比如$emit调用时传入的参数。

    • Value是处理函数(当然也可以是methods里面配置的方法名)。我们可以在Vue实例化时通过类似methods的配置项events。

    • 第25章 Webpack

      Webpack是一个模块化加载器,它同时支持AMD、CMD等加载规范。与其他模块化加载器相比,它具有以下优势:

      第26章 Rollup

      “Webpack 2输出的文件比起Rollup还是丑啊。但是Rollup针对非JS资源的插件生态不行,也没有热替换,不适合用在应用层。所以现阶段我还是用Webpack做应用层开发,用Rollup做库的打包。”

      ——尤小右

      26.1 简介

      在开发一个项目时,我们会将项目拆分成多个模块,每个模块完成相对独立的功能,我们可以很方便地单独开发代码。很可能存在这种情况:项目依赖很多第三方组件,依赖组件都很小,这对于浏览器来说是非常糟糕的,增加了许多请求;对于前端开发来说,严重影响了页面加载速度。这种情况必须规避。

      针对上面情况解决办法有很多,大多都是采用模块化开发方式,使用模块化打包工具将所有文件最终打包到一个单独的输出文件中,大大减少了请求的数量。Browserify和Webpack就是这样的打包工具。

      使用这种打包工具很快、很好、很方便。但是我们是否注意到下面这样的问题:

      第27章 Browserify

      27.1 安装

      全局安装,执行如下命名:

      $ npm i -g browserify
      

      除了全局安装,我们也可以将Browserify作为项目依赖在项目中进行安装,执行如下命令:

      $ npm i browserify --save-dev
      

      27.2 基本使用

      与Node.js支持的CommonJS规范一样,Browserify通过require来加载依赖文件。假设有如下目录结构:

      example
        |- concat.js
        |- log.js
        |- index.js
        |- index.html
      

      第28章 vue-loader

      vue-loader是基于Webpack的loader,在Vue组件化中起着决定性作用。

      28.1 如何配置

      vue-loader的配置和Webpack其他loader的配置类似,对.vue后缀增加处理。

      配置如下:

      module.exports = {
        entry: {
          app: './src/main.js'
        },
        module: {
          loaders: [
            {
              test: /\.vue$/,
              loader: 'vue'
            }
          ]
        }
      }
      

      其实配置还是非常简单、直观的。

      第29章 PostCSS

      PostCSS是一个用JavaScript插件来转换CSS的工具,目前已经有200名插件,这些插件可以lint CSS,支持变量、mixins、内联的图片等。

      简单来说,PostCSS可以将CSS转换为JavaScript能够处理的数据格式,基于JavaScript所写的插件可以完成上述各种操作。PostCSS为这些插件提供了接口,方便其完成各自的功能,但是不会对CSS代码做任何修改。从理论上讲,PostCSS的插件可以对CSS进行任何操作,只要我们有需求,就可以写一个JavaScript插件来实现。

      29.1 安装

      PostCSS针对不同的构建工具提供了不同的安装工具。在Webpack中该工具名为postcss-loader,全局安装方式如下:

      $ npm install -g postcss-loader
      

      除此之外,当需要用到PostCSS的插件时,也可以使用npm安装。比如,大名鼎鼎的autoprefixer安装方式如下:

      $ npm install autoprefixer
      

      29.2 配置

      PostCSS一般与Gulp、Webpack等构建工具搭配使用。在vue-loader中使用PostCSS时,需要在webpack.config.js中进行配置。当需要使用PostCSS的插件时,在vue选项中向postcss设置选项传入一个数组,比如使用CSSNext插件的配置代码示例如下:

      // webpack.config.js
      module.exports = {
        // other configs...
        vue: {
          // use custom postcss plugins
          postcss: [require('postcss-cssnext')()],
          // disable vue-loader autoprefixing.
          // this is a good idea since cssnext comes with it too.
          autoprefixer: false
        }
      }
      

      除了提供一个数组用于存放引用的数组外,postcss设置选项还可以接受:

      • 一个可以返回插件数组的函数。代码示例如下:
      postcss: function () {
        return [precss, autoprefixer];
      }
      
      • 一个对象,该对象包含将被传给PostCSS处理器的设置选项。代码示例如下:
      postcss: {
        plugins: [...], // list of plugins
        options: {
          parser: sugarss // use sugarss parser
        }
      }
      

      29.3 命令

      在命令行或者npm scripts中使用PostCSS需要额外安装postcss-cli,其安装方式如下:

      $ npm install postcss-cli
      

      语法如下:

      postcss [options] [-o output-file|-d output-directory|-r] [input-file]
      

      第30章 拓展篇

      30.1 Composition Event

      Composition Event,中文译为“复合事件”,是DOM 3级事件中新添加的一类事件类型,用于处理IME的输入序列。IME(Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。复合事件就是针对检测和处理这种输入而设计的。因为以上所述原因,复合事件很少被拉丁系语言输入的开发者所知(因为拉丁字母都能通过物理键盘输入)。当然,即使是使用非拉丁系语言比如中文作为输入的开发者,也不见得了解复合事件,因为在开发中用到该种事件类型的情况比较少见。

      IME复合系统的工作原理是:缓存用户的键盘输入,直到一个字符被选中后才确定输入。缓存的键盘输入会暂时展示在输入框中,但不会真正被插入到DOM中,如图30-1所示。但是如果在复合事件的过程中改变了输入框的值(比如切换了输入法或者直接按下Enter键),复合事件将提前结束,同时缓存的键盘输入值将会插入到输入框中。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJQadUiX-1593097988705)(http://localhost:8000/bf7b1d98-6e0d-43b5-9c9c-fe8b0ba7f209/OEBPS/Image00154.jpg)]

md,又是一大堆api,读完感觉,幸亏后面封装的好,这要是深刻了解源码,那内容贼多,这谁顶的住啊,了解个大概,对整体有个把我,再项目问题知道往哪边想,有工作经验之后,再回头看,这就像一本vue的历史书,慢慢的发展,慢慢的越好理解,程序并不难,但是速成难,虽然会用,但是不知道为啥会用,这是一个大多数人面临的问题,如果想提高,还是得花好多时间再那看不到提升的地方,花很多时间,对现在的我是不明智的,姑且,现在了解个大概,以后看是否技术提升,再来看看能不能npm 中造自己的轮子。。。。。

​ 2020 6 25 23:13

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值