VUE2.0进修笔记

1.媒介

装置

  • 直接用 <script> 引入(当地或许cdn)
  • npm npm install vue
  • vue-cli官方脚手架
# 全局装置 vue-cli
$ npm install --global vue-cli
# 建立一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 装置依靠,走你
$ cd my-project
$ npm install
$ npm run dev

简介

Vue (读音 /vjuː/,相似于 view) 是一套用于构建用户界面的渐进式框架。Vue 的中间库只关注视图层,对应view。

Vue数据驱动,jQuery是组织驱动

道理

内部应用Object.defineProperty(最低支撑IE9)把一切属性悉数转为 getter/setter,为每一个组件绑定了watcher 实例对象,而且把属性作为依靠项,当依靠项的setter挪用时,watcher将会从新盘算,从而更新组件。

  • [组件render]-<建立>-[getter、setter]-<网络依靠>-[watcher]
  • [触发setter]-<关照>-[watcher]-<触发>-[组件衬着函数]-<更新>-[组件]

《VUE2.0进修笔记》

《VUE2.0进修笔记》.png)

开辟环境

  • vueTools
  • vscode【Vetur、Vue2 Snippets】
  • weboack

2.实例

声明式衬着

<!--html-->
<div id="app">
  {{ message }}
</div>
//js
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

数据与要领

当一个 Vue 实例被建立时,它向 Vue 的响应式体系中加入了其 data 对象中能找到的一切的属性。当这些属性的值发作转变时,视图将会发生“响应”,即婚配更新为新的值。

// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

// 他们援用雷同的对象!
vm.a === data.a // => true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2

// ... 反之亦然
data.a = 3
vm.a // => 3

当这些数据转变时,视图会举行重衬着。值得注重的是只要当实例被建立时 data 中存在的属性是响应式的。也就是说假如你增加一个新的属性,将不会触发任何视图的更新。假如你晓得你会在晚些时刻需要一个属性,然则一最先它为空或不存在,那末你仅需要设置一些初始值。

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

// $watch 是一个实例要领
vm.$watch('a', function (newValue, oldValue) {
  // 这个回调将在 `vm.a` 转变后挪用
})

自身属性和要领

vue实例自身暴露的属性和要领经由历程前缀$来猎取

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

实例生命周期

每一个 Vue 实例在被建立之前都要经由一系列的初始化历程(生命周期)。在这个历程当中会运转一些叫做生命周期钩子的函数,用户可以在差异阶段增加自身的代码来做一些事变。
《VUE2.0进修笔记》

  • beforeCreate:在实例初始化以后,数据观察 (data observer) 和 event/watcher 事宜设置之前被挪用。
  • created:在实例建立完成后被马上挪用。在这一步,实例已完成以下的设置:数据观察 (data observer),属性和要领的运算,watch/event 事宜回调。但是,挂载阶段还没最先,$el 属性如今不可见。
  • beforeMount:在挂载最先之前被挪用:相干的 render 函数初次被挪用。
  • mounted:el 被新建立的 vm.$el 替换,并挂载到实例上去以后挪用该钩子。
  • beforeUpdate:数据更新时挪用,发作在假造 DOM 从新衬着和打补丁之前。
  • updated:由于数据更改致使的假造 DOM 从新衬着和打补丁,在这以后会挪用该钩子
  • beforeDestroy:实例烧毁之前挪用。在这一步,实例依旧完整可用。
  • destroyed:Vue 实例烧毁后挪用。挪用后,Vue 实例指导的一切东西都邑解绑定,一切的事宜监听器会被移除,一切的子实例也会被烧毁。
  • activated/deactivated:keep-alive 组件激活/停用时挪用,
  • errorCaptured:当捕捉一个来自子孙组件的毛病时被挪用。此钩子会收到三个参数:毛病对象、发作毛病的组件实例以及一个包括毛病泉源信息的字符串。此钩子可以返回 false 以阻挠该毛病继续向上流传。

注重:

  • beforeCreate,created外的钩子在服务器端衬着时期不被挪用。
  • 不要在选项属性或回调上应用箭头函数,比方
//毛病,会致使this不会指向Vue 实例
created: () => console.log(this.a)
vm.$watch('a', newValue => this.myMethod())

Vue对象的选项

var vm = new Vue({
  // 数据
  data: "声明需要响应式绑定的数据对象",
  props: "吸收来自父组件的数据",
  propsData: "建立实例时手动通报props,轻易测试props",
  computed: "盘算属性",
  methods: "定义可以经由历程vm对象接见的要领",
  watch: "Vue实例化时会挪用$watch()要领遍历watch对象的每一个属性",
  // DOM
  el: "将页面上已存在的DOM元素作为Vue实例的挂载目的",
  template: "可以替换挂载元素的字符串模板",
  render: "衬着函数,字符串模板的替换计划",
  renderError: "仅用于开辟环境,在render()涌现毛病时,供应别的的衬着输出",
  // 生命周期钩子
  beforeCreate: "发作在Vue实例初始化以后,data observer和event/watcher事宜被设置之前",
  created: "发作在Vue实例初始化以及data observer和event/watcher事宜被设置以后",
  beforeMount: "挂载最先之前被挪用,此时render()初次被挪用",
  mounted: "el被新建的vm.$el替换,并挂载到实例上以后挪用",
  beforeUpdate: "数据更新时挪用,发作在假造DOM从新衬着和打补丁之前",
  updated: "数据更改致使假造DOM从新衬着和打补丁以后被挪用",
  activated: "keep-alive组件激活时挪用",
  deactivated: "keep-alive组件停用时挪用",
  beforeDestroy: "实例烧毁之前挪用,Vue实例依旧可用",
  destroyed: "Vue实例烧毁后挪用,事宜监听和子实例悉数被移除,开释体系资本",
  // 资本
  directives: "包括Vue实例可用指令的哈希表",
  filters: "包括Vue实例可用过滤器的哈希表",
  components: "包括Vue实例可用组件的哈希表",
  // 组合
  parent: "指定当前实例的父实例,子实例用this.$parent接见父实例,父实例经由历程$children数组接见子实例",
  mixins: "将属性混入Vue实例对象,并在Vue自身实例对象的属性被挪用之前取得实行",
  extends: "用于声明继续另一个组件,从而无需应用Vue.extend,便于扩大单文件组件",
  provide&inject: "2个属性需要一同应用,用来向一切子组件注入依靠,相似于React的Context",
  // 别的
  name: "许可组件递归挪用自身,便于调试时显现越发友爱的正告信息",
  delimiters: "转变模板字符串的作风,默以为{{}}",
  functional: "让组件无状况(没有data)和无实例(没有this上下文)",
  model: "许可自定义组件应用v-model时定制prop和event",
  inheritAttrs: "默许状况下,父作用域的非props属性绑定会应用在子组件的根元素上。当编写嵌套有别的组件或元素的组件时,可以将该属性设置为false封闭这些默许行动",
  comments: "设为true时会保存而且衬着模板中的HTML解释"
});

3.模板语法

Vue.js 应用了基于 HTML 的模板语法,必需是正当的 HTML。在底层的完成上,Vue 将模板编译成假造 DOM 衬着函数。

插值

文本

<!--Mustache-->
<span>Message: {{ msg }}</span>
<!--v-text-->
<span v-text="msg"></span>
<!--v-once:一次性插值-->
<span v-once>这个将不会转变: {{ msg }}</span>

HTML

<p>Using v-html directive: <span v-html="rawHtml"></span></p>

只对可托内容应用 HTML 插值,毫不要对用户供应的内容应用插值。

特征

<div v-bind:id="dynamicId"></div>

在插值中可以应用表达式,但只限简朴表达式。

{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>

指令

指令 (Directives) 是带有 v- 前缀的特别属性。
指令的职责是,当表达式的值转变时,将其发生的连带影响,响应式地作用于 DOM。

<p v-if="seen">如今你看到我了</p>
<a v-on:click="doSomething">...</a>
指令预期/限定作用
v-textstring文本插值
v-htmlstringhtml插值
v-showany前提显现
v-if、v-else、v-else-ifany前提衬着
v-forArray/Object/number/string列表衬着
v-on(@)Function/Inline Statement/Object事宜绑定
v-bind(:)any (with argument)/Object (without argument)特征绑定
v-model仅限<input>/<select>/<textarea>/components元素应用双向绑定
v-pre疏忽编译
v-cloak防止显现Mustache
v-once一次性衬着

润饰符

润饰符 (Modifiers) 是以半角句号 . 指明的特别后缀,用于指出一个指令应当以特别体式格局绑定。

<form v-on:submit.prevent="onSubmit">...</form>
  • v-on能应用的润饰符:
润饰符作用
.stop挪用 event.stopPropagation()。
.prevent挪用 event.preventDefault()。
.capture增加事宜侦听器时应用 capture 情势。
.self只当事宜是从侦听器绑定的元素自身触发时才触发还调。
.{keyCode / keyAlias}只当事宜是从特定键触发时才触发还调。
.native监听组件根元素的原生事宜。
.once只触发一次回调。
.left(2.2.0) 只当点击鼠标左键时触发。
.right(2.2.0) 只当点击鼠标右键时触发。
.middle(2.2.0) 只当点击鼠标中键时触发。
.passive(2.3.0) 以 { passive: true } 情势增加侦听器
  • v-bind能应用的润饰符:
润饰符作用
.prop被用于绑定 DOM 属性 (property)。(差异在那里?)
.camel(2.1.0+) 将 kebab-case 特征名转换为 camelCase. (从 2.1.0 最先支撑)
.sync(2.3.0+) 语法糖,会扩大成一个更新父组件绑定值的 v-on 侦听器。
  • v-model能应用的润饰符:
润饰符作用
.lazy庖代 input 监听 change 事宜
.number输入字符串转为数字
.trim输入首尾空格过滤

4.盘算属性和观察者

盘算属性

关于任何庞杂逻辑,你都应当应用盘算属性,而不该直接放在模板中。

盘算属性也是响应式的,然则它会基于它们的依靠举行缓存的,只要当缓存转变,它才会从新求值;不然会直接返回缓存的结果,而没必要再次实行函数。

应当优先应用盘算属性而不是侦听属性。

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 盘算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

下面的盘算属性不会更新,由于Date.now() 不是响应式依靠。

computed: {
  now: function () {
    return Date.now()
  }
}

盘算属性缓存 vs 要领

<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在组件中
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

要领在每次挪用时总会再次实行函数

setter

盘算属性默许只要 getter ,不过在需要时你也可以供应一个 setter

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

侦听器

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
watch: {
    // 假如 `question` 发作转变,这个函数就会运转
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.getAnswer()
    }
  }

烧毁

// const unWatch = app.$watch('text', (newText, oldText) => {
//   console.log(`${newText} : ${oldText}`)
// })
// setTimeout(() => {
//   unWatch()
// }, 2000)

5. Class与Style绑定

Class

对象语法

当value为真时,绑定对应的key到class

<!--内联在模板中-->
<div class="static"
     v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
<!--绑定data或许盘算属性的的一个对象-->
<div v-bind:class="classObject"></div>
<!--js-->
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

数组语法

<!--模板-->
<div v-bind:class="[activeClass, errorClass]"></div>
<!--js-->
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
<!--结果-->
<div class="active text-danger"></div>

也可以应用三元表达式。

// isActive为真增加activeClass,errorClass一直存在
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

夹杂

<div v-bind:class="[{ active: isActive }, errorClass]"></div>

用在组件上

class将被增加到该组件的根元素上面。该元素上已存在的class不会被掩盖。

<my-component class="baz boo"></my-component>

注重:和一般的class并存,并不会掩盖(差异名),终究会合成一个class。

Style

自动侦测并增加响应浏览器引擎前缀。

对象语法

CSS 属性名可以用驼峰式 (camelCase) 或短横线分开 (kebab-case,记得用单引号括起来) 来定名。

<!--内联在模板中-->
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<!--js-->
data: {
  activeColor: 'red',
  fontSize: 30
}
<!--绑定data或许盘算属性的的一个对象-->
<div v-bind:style="styleObject"></div>
<!--js-->
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

数组语法

可以将多个款式对象应用到统一个元素上

<div v-bind:style="[baseStyles, overridingStyles]"></div>

多重值

<!--常用于供应多个带前缀的值-->
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

6.前提衬着

v-if(v-else、v-else-if)

依据表达式的值的真假前提衬着元素。

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

假如需要前提衬着多个元素,可以应用<template>包裹。

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

Vue 会尽量高效地衬着元素,通常会复用已有元素而不是从头最先衬着。增加一个具有唯一值的 key 属性可以强迫其从新衬着。

v-show

依据表达式之真假值,切换元素的 display CSS 属性。

<h1 v-show="ok">Hello!</h1>

7.列表衬着

数组

<!--一般-->
<ul id="example">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
<!--带索引-->
<ul id="example">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
<!--js-->
var example = new Vue({
  el: '#example',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

数组更新检测

包括变异(转变原数组)和非变异(天生新数组,不转变原数组)两组体式格局,都将触发更新。

  • 变异要领:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 非变异要领(需用新数组替换原数组):filter()、concat()、slice()

不能检测的更改:

  • 当你应用索引直接设置一个项时,比方:vm.items[indexOfItem] = newValue
  • 当你修正数组的长度时,比方:vm.items.length = newLength

对象

<!--一般-->
<li v-for="value in object">
{{ value }}
</li>
<!--带key-->
<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>
<!--带key、索引-->
<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>
<!--js-->
new Vue({
  data: {
    object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
  }
})

对象更改检测注重事项

Vue 不能检测对象属性的增加或删除。

  • 关于已建立的实例,Vue 不能动态增加根级别的响应式属性。
var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 如今是响应式的

vm.b = 2
// `vm.b` 不是响应式的
  • 可以应用 Vue.set(object, key, value) 要领向嵌套对象增加响应式属性
var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})
vm.$set(this.userProfile, 'age', 27)
  • 多个属性可以应用Object.assign() 或 _.extend()
this.userProfile = Object.assign({}, this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

delete

对应的删除属性应用vm.$delete(obj,key)

key

当 Vue.js 用 v-for 正在更新已衬着过的元素列表时,它默许用“当场复用”战略。
发起尽量在应用 v-for 时为每一项供应一个唯一的 key。
轮回组件的时刻,key是必需的。

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

其他

  • v-for的轮回对象也可以是盘算属性和带返回值的method 要领。
  • 应用带有 v-for 的 <template> 衬着多个元素
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>
  • v-for和v-if处于统一节点时,v-for 具有比 v-if 更高的优先级

8.事宜处置惩罚

事宜

<div id="example-3">
  <button v-on:click="say('hi')">Say hi</button>
  <!--接见原始的 DOM 事宜-->
  <button v-on:click="say2('what', $event)">Say what</button>
</div>
new Vue({
  el: '#example-3',
  methods: {
    say: function (message) {
      alert(message)
    },
    say2: function (message,event) {
        // 如今我们可以接见原生事宜对象
        if (event) event.preventDefault()
      alert(message)
    }
  }
})

事宜润饰符

润饰符可以串连,代码会以串连的递次发生。

润饰符作用
.stop挪用 event.stopPropagation()。
.prevent挪用 event.preventDefault()。
.capture增加事宜侦听器时应用 capture 情势。
.self只当事宜是从侦听器绑定的元素自身触发时才触发还调。
.once只触发一次回调。
<!-- 阻挠单击事宜继续流传 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事宜不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 润饰符可以串连 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只要润饰符 -->
<form v-on:submit.prevent></form>

<!-- 增加事宜监听器时应用事宜捕捉情势 -->
<!-- 即元素自身触发的事宜先在此处处置惩罚,然后才交由内部元素举行处置惩罚 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处置惩罚函数 -->
<!-- 即事宜不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事宜将只会触发一次(可用于自定义组件) -->
<a v-on:click.once="doThis"></a>

Vue 还对应 addEventListener 中的 passive 选项供应了 .passive 润饰符,可以提拔挪动端的机能,然则要防止和.prevent一同应用。

<!-- 转动事宜的默许行动 (即转动行动) 将会马上触发 -->
<!-- 而不会守候 `onScroll` 完成  -->
<!-- 这个中包括 `event.preventDefault()` 的状况 -->
<div v-on:scroll.passive="onScroll">...</div>

按键润饰符

在监听键盘事宜时,我们常常需要搜检罕见的键值。Vue 许可为 v-on 在监听键盘事宜时增加按键润饰符。

<!-- 只要在 `keyCode` 是 13 时挪用 `vm.submit()` -->
<input v-on:keyup.13="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
  • 悉数的按键别号:.enter.tab.delete (捕捉“删除”和“退格”键)、.esc.space.up.down.left.right
  • 自定义按键润饰符别号
// 可以应用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
  • 自动婚配按键润饰符
<!--可直接将 KeyboardEvent.key 暴露的恣意有效按键名转换为 kebab-case 来作为润饰符:-->
<input @keyup.page-down="onPageDown">

体系润饰键

.ctrl.alt.shift.meta
在和 keyup 事宜一同用时,事宜触发时润饰键必需处于按下状况。换句话说,只要在按住 ctrl 的状况下开释别的按键,才触发 keyup.ctrl。而单单开释 ctrl 也不会触发事宜。

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

.exact 润饰符许可你掌握由准确的体系润饰符组合触发的事宜。

<!-- 纵然 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只要 Ctrl 被按下的时刻才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何体系润饰符被按下的时刻才触发 -->
<button @click.exact="onClick">A</button>

鼠标按钮润饰符

.left.right.middle
仅响应特定的鼠标按钮

9.表单输入绑定

基本用法

可以用 v-model 指令在表单 <input><textarea> 元素上建立双向数据绑定。

v-model仅为v-on:inputv-bind:value语法糖罢了。

<input v-model="something">
<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">

注重:v-model 会疏忽一切表单元素的 value、checked、selected 特征的初始值而老是将 Vue 实例的数据作为数据泉源。你应当经由历程 JavaScript 在组件的 data 选项中声明初始值。

  • 文本/多行文本
<input v-model="message" placeholder="edit me">
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<p>Message is: {{ message }}</p>
  • 复选框
<div id='example-3'>
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames">
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
  <label for="mike">Mike</label>
  <br>
  <span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
  el: '#example-3',
  data: {
    checkedNames: []
  }
})
//Checked names: [ "Jack", "John", "Mike" ]
  • 单选按钮
<div id="example-4">
  <input type="radio" id="one" value="One" v-model="picked">
  <label for="one">One</label>
  <br>
  <input type="radio" id="two" value="Two" v-model="picked">
  <label for="two">Two</label>
  <br>
  <span>Picked: {{ picked }}</span>
</div>
new Vue({
  el: '#example-4',
  data: {
    picked: ''
  }
})
//Picked: Two
  • 挑选框
<div id="example-5">
  <select v-model="selected">
    <option disabled value="">请挑选</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})
//Selected: B

为多选时则返回一个数组Selected: [ "A", "B" ]

值绑定

  • 复选框
<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>
  • 单选按钮
<input type="radio" v-model="pick" v-bind:value="a">
  • 挑选框的选项
<select v-model="selected">
    <!-- 内联对象字面量 -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>

润饰符

  • .lazy,默许input事宜触发,应用此润饰则改成change事宜触发
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >
  • .number将输入的值转换为数值
  • .trim过滤掉输入内容的首尾空缺字符

10.组件

简介

《VUE2.0进修笔记》
组件 (Component) 是 Vue.js 最壮大的功用之一。组件可以扩大 HTML 元素,封装可重用的代码。组件是具有特别功用的自定义元素。

一切的 Vue 组件同时也都是 Vue 的实例,所以可接收雷同的选项对象 (除了一些根级特有的选项) 并供应雷同的生命周期钩子。

注册组件

全局组件

<div id="example">
  <my-component></my-component>
</div>
//注重确保在初始化根实例之前注册组件
// 注册
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

部分组件

var Child = {
  template: '<div>A custom component!</div>'
}

new Vue({
  // ...
  components: {
    // <my-component> 将只在父组件模板中可用
    'my-component': Child
  }
})

自动注册

webpack 的 vue cli3+

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // 其组件目次的相对门路
  './components',
  // 是不是查询其子目次
  false,
  // 婚配基本组件文件名的正则表达式
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // 猎取组件设置
  const componentConfig = requireComponent(fileName)

  // 猎取组件的 PascalCase 定名
  const componentName = upperFirst(
    camelCase(
      // 剥去文件名开首的 `'./` 和末端的扩大名
      fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
    )
  )

  // 全局注册组件
  Vue.component(
    componentName,
    // 假如这个组件选项是经由历程 `export default` 导出的,
    // 那末就会优先应用 `.default`,
    // 不然回退到应用模块的根。
    componentConfig.default || componentConfig
  )
})
注重
  • data必需是带return的函数
  • 假如将组件用于像 <ul><ol><table><select> 如许的元素内里,为了遵照范例,应当应用is:
<table>
  <tr is="my-row"></tr>
</table>

以下范例模板无此限定:<script type="text/x-template">、JavaScript 内联模板字符串、.vue 组件

单文件组件

可以包括<template><script><style><docs>四个元素。

  • <template>内只许可有一个根元素
  • <style>可以有多个
  • <docs>申明文档
  • <script><style>支撑src导入

组件通讯

《VUE2.0进修笔记》

Prop

父组件向子组件通报数据。

Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 就像 data 一样,prop 也可以在模板中应用
  // 一样也可以在 vm 实例中经由历程 this.message 来应用
  template: '<span>{{ message }}</span>'
})
<child message="hello!"></child>
动态 Prop:
<child v-bind:my-message="parentMsg"></child>

假如你想把一个对象的一切属性作为 prop 举行通报,可以应用不带任何参数的 v-bind

todo: {
  text: 'Learn Vue',
  isComplete: false
}
<todo-item v-bind="todo"></todo-item>
//等价于
<todo-item
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"
></todo-item>
字面量语法 vs 动态语法
<!-- 通报了一个字符串 "1" -->
<comp some-prop="1"></comp>
<!-- 通报真正的数值 -->
<comp v-bind:some-prop="1"></comp>
考证

为组件的 prop 指定考证划定规矩,会在组件实例建立之前举行校验。假如传入的数据不符合请求,Vue 会发出正告。

Vue.component('example', {
  props: {
    // 基本范例检测 (`null` 指许可任何范例)
    propA: Number,
    // 多是多种范例
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数值且有默许值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默许值应当由一个工场函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义考证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

type 可以是下面原生组织器StringNumberBooleanFunctionObjectArraySymbol

组件可以吸收恣意传入的特征,这些特征都邑被增加到组件的根元素上,且会做兼并处置惩罚。

自定义事宜

子组件向父组件通报数据。

  • 应用 $on(eventName) 监听事宜
  • 应用 $emit(eventName) 触发事宜
<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
Vue.component('button-counter', {
  template: '<button v-on:click="incrementCounter">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementCounter: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})

new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})

父子双向通讯

  • .sync

@update的语法糖

<comp :foo.sync="bar"></comp>
this.$emit('update:foo', newValue)

等价于

<comp :foo="bar" @update:foo="val => bar = val"></comp>
this.$emit('update:foo', newValue)
  • v-model(仅实用于表单输入组件)

v-on:inputv-bind:value的语法糖

<input v-model="something">
// 经由历程 input 事宜带出数值
this.$emit('input', Number(formattedValue))

等价于

<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">
this.$emit('input', Number(formattedValue))

非父子组件通讯

  • 简朴场景bus.js
var bus = new Vue()
// 触发组件 A 中的事宜
bus.$emit('id-selected', 1)
// 在组件 B 建立的钩子中监听事宜
bus.$on('id-selected', function (id) {
  // ...
})

注: 还可以应用$ref、$parent、$child举行通讯,不过不引荐

  • 庞杂的场景请应用vuex

插槽

为了让组件可以组合,我们需要一种体式格局来夹杂父组件的内容与子组件自身的模板。这个历程被称为内容分发。
编译作用域: 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。

单个插槽

除非子组件模板包括最少一个 <slot> 插口,不然父组件的内容将会被扬弃。当子组件模板只要一个没有属性的插槽时,父组件传入的全部内容片断将插进去到插槽地点的 DOM 位置,并替换掉插槽标签自身。

最初在 <slot> 标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,而且只要在宿主元素为空,且没有要插进去的内容时才显现备用内容。

<!--子组件-->
<div>
  <h2>我是子组件的题目</h2>
  <slot>
    只要在没有要分发的内容时才会显现。
  </slot>
</div>

<!--父组件-->
<div>
  <h1>我是父组件的题目</h1>
  <my-component>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </my-component>
</div>

<!--结果-->
<div>
  <h1>我是父组件的题目</h1>
  <div>
    <h2>我是子组件的题目</h2>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </div>
</div>

签字插槽

<slot> 元素可以用一个特别的特征 name 来进一步设置怎样分发内容。多个插槽可以有差异的名字。签字插槽将婚配内容片断中有对应 slot 特征的元素。

依旧可以有一个匿名插槽,它是默许插槽,作为找不到婚配的内容片断的备用插槽。假如没有默许插槽,这些找不到婚配的内容片断将被扬弃。

<!--子组件-->
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

<!--父组件-->
<app-layout>
  <h1 slot="header">这里多是一个页面题目</h1>

  <p>重要内容的一个段落。</p>
  <p>另一个重要段落。</p>

  <p slot="footer">这里有一些联络信息</p>
</app-layout>

<!--结果-->
<div class="container">
  <header>
    <h1>这里多是一个页面题目</h1>
  </header>
  <main>
    <p>重要内容的一个段落。</p>
    <p>另一个重要段落。</p>
  </main>
  <footer>
    <p>这里有一些联络信息</p>
  </footer>
</div>

作用域插槽

和一般的插槽对照,可以通报数据。

<!--子组件-->
<div class="child">
  <slot text="hello from child"></slot>
</div>

<!--父组件-->
<div class="parent">
  <child>
  <!--2.5.0+,slot-scope 能被用在恣意元素或组件中而不再局限于 <template>-->
    <template slot-scope="props">
      <span>hello from parent</span>
      <span>{{ props.text }}</span>
    </template>
  </child>
</div>

<!--结果-->
<div class="parent">
  <div class="child">
    <span>hello from parent</span>
    <span>hello from child</span>
  </div>
</div>

动态组件

经由历程应用保存的 <component> 元素,并对其 is 特征举行动态绑定,你可以在统一个挂载点动态切换多个组件:

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})

keep-alive

把切换出去的组件保存在内存中,保存其状况或防止从新衬着

<keep-alive>
  <component :is="currentView">
    <!-- 非运动组件将被缓存! -->
  </component>
</keep-alive>

注重事项

  • 组件复用性,松耦合
  • 郑重应用ref
  • 在大型应用中应用异步加载
  • PascalCase声明, kebab-case应用
  • 为递归组件增加name
  • 对低开支的静态组件应用 v-once

11.过渡和动画

Vue 在插进去、更新或许移除 DOM 时,供应多种差异体式格局的应用过渡结果。

单元素/组件的过渡

实用场景:前提衬着 (应用 v-if)、前提展现 (应用 v-show)、动态组件、组件根节点

<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

过渡的类名

  • v-enter:定义进入过渡的最先状况。在元素被插进去时见效,鄙人一个帧移除。
  • v-enter-active:定义过渡的状况。在元素全部过渡历程当中作用,在元素被插进去时见效,在 transition/animation 完成以后移除。这个类可以被用来定义过渡的历程时候,耽误和曲线函数。
  • v-enter-to: 2.1.8版及以上 定义进入过渡的完毕状况。在元素被插进去一帧后见效 (与此同时 v-enter 被删除),在 transition/animation 完成以后移除。
  • v-leave: 定义脱离过渡的最先状况。在脱离过渡被触发时见效,鄙人一个帧移除。
  • v-leave-active:定义过渡的状况。在元素全部过渡历程当中作用,在脱离过渡被触发后马上见效,在 transition/animation 完成以后移除。这个类可以被用来定义过渡的历程时候,耽误和曲线函数。
  • v-leave-to: 2.1.8版及以上 定义脱离过渡的完毕状况。在脱离过渡被触发一帧后见效 (与此同时 v-leave 被删除),在 transition/animation 完成以后移除。

《VUE2.0进修笔记》

动画

动画在css中应用animation即可,其他和过渡相似。

自定义过渡的类名

我们可以经由历程以下特征来自定义过渡类名:
enter-class、enter-active-class、enter-to-class (2.1.8+)、leave-class、leave-active-class、leave-to-class (2.1.8+)

<div id="example-3">
  <button @click="show = !show">
    Toggle render
  </button>
  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>
</div>

设定持续时候

<transition :duration="1000">...</transition>
<transition :duration="{ enter: 500, leave: 800 }">...</transition>

JavaScript 钩子

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
// ...
methods: {
  // --------
  // 进入中
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // 此回调函数是可选项的设置,done 是必需的 
  // 与 CSS 结应时应用
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // 脱离时
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // 此回调函数是可选项的设置,done 是必需的 
  // 与 CSS 结应时应用
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}

初始衬着的过渡

可以经由历程 appear 特征设置节点在初始衬着的过渡

<!--css-->
<transition
  appear
  appear-class="custom-appear-class"
  appear-to-class="custom-appear-to-class" (2.1.8+)
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>
<!--JS钩子-->
<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>

多个元素的过渡

当有雷同标署名的元素切换时,发起给元素设置key。

过渡情势

  • in-out:新元素先举行过渡,完成以后当前元素过渡脱离。
  • out-in:当前元素先举行过渡,完成以后新元素过渡进入。
<transition name="fade" mode="out-in">
  <!-- ... the buttons ... -->
</transition>

多个组件的过渡

多个组件的过渡应用动态组件

<!--html-->
<transition name="component-fade" mode="out-in">
  <component v-bind:is="view"></component>
</transition>
<!--js-->
new Vue({
  el: '#transition-components-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})

列表过渡

应用 <transition-group> 组件。

  • 它会以一个实在元素显现:默以为一个 <span>。你也可以经由历程 tag 特征更换为其他元素。
  • 内部元素 老是需要 供应唯一的 key 属性值
<div id="list-demo" class="demo">
  <button v-on:click="add">Add</button>
  <button v-on:click="remove">Remove</button>
  <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
      {{ item }}
    </span>
  </transition-group>
</div>

<transition-group> 组件另有一个特别的处所。不仅可以进入和脱离动画,还可以转变定位。v-move 特征,它会在元素的转变定位的历程当中应用。

<!--html-->
<transition-group name="flip-list" tag="ul">
    <li v-for="item in items" v-bind:key="item">
      {{ item }}
    </li>
</transition-group>
<!--css-->
.flip-list-move {
  transition: transform 1s;
}

也可以经由历程 move-class 属性手动设置

技能

  • 建立可复用过分组件,将 <transition> 或许 <transition-group> 作为根组件
<transition
    name="very-special-transition"
    mode="out-in"
    v-on:before-enter="beforeEnter"
    v-on:after-enter="afterEnter">
    <slot></slot>
</transition>
  • 动态过渡,经由历程动态绑定name完成
<transition v-bind:name="transitionName">
  <!-- ... -->
</transition>

12.可复用性和组合

夹杂

夹杂 (mixins) 是一种分发 Vue 组件中可复用功用的异常天真的体式格局。夹杂对象可以包括恣意组件选项。当组件应用夹杂对象时,一切夹杂对象的选项将被混入该组件自身的选项。

// 定义一个夹杂对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// 定义一个应用夹杂对象的组件
var Component = Vue.extend({
  mixins: [myMixin]
})
  • 当组件和夹杂对象含有同名选项时,这些选项将以适当的体式格局夹杂。比方,同名钩子函数将夹杂为一个数组,因而都将被挪用。别的,夹杂对象的 钩子将在组件自身钩子 之前 挪用 。
  • 值为对象的选项,比方 methods, components 和 directives,将被夹杂为统一个对象。两个对象键名争执时,取组件对象的键值对。
  • Vue.extend() 也应用一样的战略举行兼并。

自定义指令

除了中间功用默许内置的指令 (v-model 和 v-show),Vue 也许可注册自定义指令。

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插进去到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
// 注册一个部分自定义指令
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}
//应用
<input v-focus>

钩子函数

一个指令定义对象可以供应以下几个钩子函数 (均为可选):

  • bind:只挪用一次,指令第一次绑定到元素时挪用。在这里可以举行一次性的初始化设置。
  • inserted:被绑定元素插进去父节点时挪用 (仅保证父节点存在,但不肯定已被插进去文档中)。
  • update:地点组件的 VNode 更新时挪用,然则可以发作在其子 VNode 更新之前。指令的值可以发作了转变,也可以没有。然则你可以经由历程比较更新前后的值来疏忽没必要要的模板更新 (细致的钩子函数参数见下)。
  • componentUpdated:指令地点组件的 VNode 及其子 VNode 悉数更新后挪用。
  • unbind:只挪用一次,指令与元素解绑时挪用。

钩子函数参数

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操纵 DOM 。
  • binding:一个对象,包括以下属性:

    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,比方:v-my-directive=”1 + 1″ 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。不管值是不是转变都可用。
    • expression:字符串情势的指令表达式。比方 v-my-directive=”1 + 1″ 中,表达式为 “1 + 1″。
    • arg:传给指令的参数,可选。比方 v-my-directive:foo 中,参数为 “foo”。
    • modifiers:一个包括润饰符的对象。比方:v-my-directive.foo.bar 中,润饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译天生的假造节点。移步 VNode API 来相识更多概况。
  • oldVnode:上一个假造节点,仅在 update 和 componentUpdated 钩子中可用。

衬着函数 & JSX

https://cn.vuejs.org/v2/guide…

衬着函数render

createElement

// @returns {VNode}
createElement(
  // {String | Object | Function}
  // 一个 HTML 标签字符串,组件选项对象,或许
  // 剖析上述任何一种的一个 async 异步函数,必要参数。
  'div',

  // {Object}
  // 一个包括模板相干属性的数据对象
  // 如许,您可以在 template 中应用这些属性。可选参数。
  {
    // (概况见下面的数据对象)
  },

  // {String | Array}
  // 子节点 (VNodes),由 `createElement()` 构建而成,
  // 或应用字符串来天生“文本节点”。可选参数。
  [
    '先写一些笔墨',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

数据对象:

{
  // 和`v-bind:class`一样的 API
  'class': {
    foo: true,
    bar: false
  },
  // 和`v-bind:style`一样的 API
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 一般的 HTML 特征
  attrs: {
    id: 'foo'
  },
  // 组件 props
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事宜监听器基于 `on`
  // 所以不再支撑如 `v-on:keyup.enter` 润饰器
  // 需要手动婚配 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅关于组件,用于监听原生事宜,而不是组件内部应用
  // `vm.$emit` 触发的事宜。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注重,你没法对 `binding` 中的 `oldValue`
  // 赋值,由于 Vue 已自动为你举行了同步。
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // Scoped slots in the form of
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 假如组件是其他组件的子组件,需为插槽指定称号
  slot: 'name-of-slot',
  // 其他特别顶层属性
  key: 'myKey',
  ref: 'myRef'
}

过滤器

过滤器可以用在两个处所:双花括号插值和 v-bind 表达式。

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
//定义部分过滤器
filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}
//定义全局过滤器
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
  • 过滤器可以串连,顺次实行,前面的输出作为背面一个的输入。
{{ message | filterA | filterB }}
  • 过滤器可以吸收参数(管道符前面的值作为第一个参数,括号内的第一个参数为第二个,顺次类推)
{{ message | filterA('arg1', arg2) }}

13.Vue-Router

装置

  • 直接用 <script> 引入(当地或许cdn)
  • npm npm install vue

必需要经由历程 Vue.use() 明确地装置路由功用,且要经由历程 router 设置参数注入Vue实例,从而让全部应用都有路由功用。

作用

将页面组件(components)映照到路由(routes),然后通知 vue-router 在那里衬着它们

router-link

  • to: 属性指定目的地点,默许衬着成带有准确链接的 标签,
  • replace:相当于router.replace() 不会留下 history 纪录
  • append:设置 append 属性后,则在当前(相对)门路前增加基门路。比方,我们从 /a 导航到一个相对门路 b,假如没有设置 append,则门路为 /b,假如配了,则为 /a/b
  • tag: 属性天生别的标签.。别的,当目的路由胜利激活时,链接元素自动设置一个示意激活的 CSS 类名。
  • active-class:链接激活时应用的 CSS 类名。默许值可以经由历程路由的组织选项 linkActiveClass 来全局设置。

    将激活 class 应用在外层元素:

<router-link tag="li" to="/foo">
  <a>/foo</a>
</router-link>

在这类状况下,<a> 将作为实在的链接(它会取得准确的 href 的),而 “激活时的CSS类名” 则设置到外层的 <li>

router-view

路由视图容器

<transition>
<!--应用路由缓存-->
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

假如 <router-view>设置了称号,则会衬着对应的路由设置中 components 下的响应组件。

<!--html-->
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
<!--js-->
const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})

动态路由婚配

  • 动态门路参数params
//定义
routes: [
    // 动态门路参数 以冒号开首
    { path: '/user/:id', component: User }
  ]
//挪用
$route.params.id
  • 动态门路查询参数query
//定义
routes: [
    // 动态门路参数 以冒号开首
    { path: '/user?id=6456456', component: User }
  ]
//挪用
$route.query.id
  • 区分:params定义了就是路由的一部分,就必需要传,不然婚配失利,query可以缺省

响应路由参数的变化

当路由参数变化时,组件的生命周期钩子不会再被挪用。
想对路由参数的变化作出响应的话,有以下两种体式格局:

  • watch(监测变化) $route 对象:
const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应...
    }
  }
}
  • 应用beforeRouteUpdate 守御:
const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

婚配优先级

统一个门路可以婚配多个路由时,谁先定义的,谁的优先级就最高。
因而,404类的页面肯定要放在末了,路由是根据声明递次婚配,假如不是末了则404以后的页面都邑跳转到404。

嵌套路由

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 当 /user/:id/profile 婚配胜利,
          // UserProfile 会被衬着在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 当 /user/:id/posts 婚配胜利
          // UserPosts 会被衬着在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})
  • 以 / 开首的嵌套门路会被看成根门路。 这让你充足的应用嵌套组件而无须设置嵌套的门路。
  • 假如想在父路由衬着内容,可以定义一个空的子路由。

编程式的导航

router.push(location, onComplete?, onAbort?)

导航到差异的 URL,会向 history 栈增加一个新的纪录。
在 Vue 实例内部,挪用 this.$router.push

// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 定名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
  • onComplete:在导航胜利完成 (在一切的异步钩子被剖析以后) 挪用
  • onAbort:在导航停止 (导航到雷同的路由、或在当前导航完成之前导航到另一个差异的路由) 挪用

router.replace(location, onComplete?, onAbort?)

和router.push功用一样,唯一区分就是不会向 history 增加新纪录

router.go(n)

行进或退却nN步,相似 window.history.go(n)

// 在浏览器纪录中行进一步,等同于 history.forward()
router.go(1)
// 退却一步纪录,等同于 history.back()
router.go(-1)

重定向

const router = new VueRouter({
  routes: [
    //path
    { path: '/a', redirect: '/b' },
    //name
    { path: '/a', redirect: { name: 'foo' }},
    //要领
    { path: '/a', redirect: to => {
      // 要领吸收 目的路由 作为参数
      // return 重定向的 字符串门路/门路对象
    }}
  ]
})

别号

/a 的别号是 /b,意味着,当用户接见 /b 时,URL 会坚持为 /b,然则路由婚配则为 /a,就像用户接见 /a 一样

const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})

路由组件传参

应用 props 将组件和路由解耦

const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 关于包括定名视图的路由,你必需分别为每一个定名视图增加 `props` 选项:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})
  • 假如 props 被设置为 true,route.params 将会被设置为组件属性
  • 假如 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时刻有效。
const router = new VueRouter({
  routes: [
    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
  ]
})
  • 你可以建立一个函数返回 props。如许你便可以将参数转换成另一种范例,将静态值与基于路由的值连系等等。
const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
  ]
})

HTML5 History 情势

vue-router 默许 hash 情势。

开启history 情势,将充足应用 history.pushState API 来完成 URL 跳转而无须从新加载页面,但需要后端合营。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

导航守御

vue-router 供应的导航守御重要用来经由历程跳转或作废的体式格局守御导航。

全局

//前置守御:确保要挪用 next 要领,不然钩子就不会被 resolved。
router.beforeEach((to, from, next) => {
  // ...
})
//后置守御
router.afterEach((to, from) => {
  // ...
})
//剖析守御:在导航被确认之前,同时在一切组件内守御和异步路由组件被剖析以后,剖析守御就被挪用
router.beforeResolve((to, from) => {
  // ...
})
参数申明
  • to: Route: 行将要进入的目的 路由对象
  • from: Route: 当前导航正要脱离的路由
  • next: Function: 肯定要挪用该要领来 resolve 这个钩子。实行结果依靠 next 要领的挪用参数。

    • next(): 举行管道中的下一个钩子。假如悉数钩子实行完了,则导航的状况就是 confirmed (确认的)。
    • next(false): 中缀当前的导航。假如浏览器的 URL 转变了(多是用户手动或许浏览器退却按钮),那末 URL 地点会重置到 from 路由对应的地点。
    • next('/') 或许 next({ path: '/' }): 跳转到一个差异的地点。当前的导航被中缀,然后举行一个新的导航。你可以向 next 通报恣意位置对象,且许可设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
    • next(error): (2.4.0+) 假如传入 next 的参数是一个 Error 实例,则导航会被停止且该毛病会被通报给 router.onError() 注册过的回调。

路由独享的守御

//与全局前置守御的要领参数是一样的
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

组件内的守御

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在衬着该组件的对应路由被 confirm 前挪用
    // 不!能!猎取组件实例 `this`
    // 由于当守御实行前,组件实例还没被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由转变,然则该组件被复用时挪用
    // 举例来说,关于一个带有动态参数的门路 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时刻,
    // 由于会衬着一样的 Foo 组件,因而组件实例会被复用。而这个钩子就会在这个状况下被挪用。
    // 可以接见组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航脱离该组件的对应路由时挪用
    // 可以接见组件实例 `this`
  }
}

beforeRouteEnter 守御 不能 接见 this,由于守御在导航确认前被挪用,因而行将上台的新组件还没被建立。可以经由历程传一个回调给 next来接见组件实例。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 经由历程 `vm` 接见组件实例
  })
}

剖析流程

  1. 导航被触发。
  2. 在失活的组件里挪用脱离守御。
  3. 挪用全局的 beforeEach 守御。
  4. 在重用的组件里挪用 beforeRouteUpdate 守御 (2.2+)。
  5. 在路由设置里挪用 beforeEnter。
  6. 剖析异步路由组件。
  7. 在被激活的组件里挪用 beforeRouteEnter。
  8. 挪用全局的 beforeResolve 守御 (2.5+)。
  9. 导航被确认。
  10. 挪用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用建立好的实例挪用 beforeRouteEnter 守御中传给 next 的回调函数。

路由元信息

设置meta字段纪录元信息

//定义
{
  path: 'bar',
  component: Bar,
  // a meta field
  meta: { requiresAuth: true }
}
//接见
$route.matched

过渡动效

<transition>
  <router-view></router-view>
</transition>
<!-- 应用动态的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>

14.Vuex

装置

  • 直接用 <script> 引入(当地或许cdn)
  • npm npm install vuex

必需要经由历程 Vue.use() 明确地装置vuex,且要经由历程 store 设置参数注入Vue实例。

简介

Vuex 是一个专为 Vue.js 应用程序开辟的状况治理情势。它采纳集中式存储治理应用的一切组件的状况,并以响应的划定规矩保证状况以一种可展望的体式格局发作变化。

《VUE2.0进修笔记》

state

  • 状况堆栈,全局的数据同享中间
  • 转变 state 中的状况的唯一门路就是显式地提交 (commit) mutation
  • 猎取状况应用盘算属性
  • mapState辅佐函数
// 在零丁构建的版本中辅佐函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可以使代码更精练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了可以应用 `this` 猎取部分状况,必需应用通例函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}
--------------
//当映照的盘算属性的称号与 state 的子节点称号雷同时,我们也可以给 mapState 传一个字符串数组
computed: mapState([
  // 映照 this.count 为 store.state.count
  'count'
])
--------------
computed: {
  localComputed () { /* ... */ },
  // 应用对象睁开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}

Getters

假如有多处都需要从store中派生(举行二次处置惩罚)出一些状况,那末可以应用getter(store 的盘算属性,依靠更新)

getters: {
    //state 作为其第一个参数
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    },
    //接收其他 getter 作为第二个参数
    doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
//挪用
store.getters.doneTodosCount // -> 1
  • mapGetters辅佐函数将 store 中的 getter 映照到部分盘算属性,用法和mapState一样
import { mapGetters } from 'vuex'
computed: {
    // 应用对象睁开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
}

Mutations

更改 Vuex 的 store 中的状况的唯一要领是提交 (commit)。发起名字大写。 mutation,然则请勿举行异步操纵。

mutations: {
    increment (state) {
      // 变动状况
      state.count++
    }
}
//挪用
store.commit('increment')
  • 提交载荷(Payload)

载荷即commit中分外的参数。

mutations: {
  increment (state, n) {
    state.count += n
  }
}
//挪用
store.commit('increment', 10)
-------------
//引荐应用对象
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment', {
  amount: 10
})
//对象作风提交
store.commit({
  type: 'increment',
  amount: 10
})
  • mapMutations 辅佐函数将组件中的 methods 映照为 store.commit 挪用
import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映照为 `this.$store.commit('increment')`

      // `mapMutations` 也支撑载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映照为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映照为 `this.$store.commit('increment')`
    })
  }
}

Actions

Action 相似于 mutation,区分在于:

  • Action 提交的是 mutation,而不是直接变动状况。
  • Action 可以包括恣意异步操纵。
actions: {
    increment (context) {
      context.commit('increment')
    }
}
//分发
store.dispatch('increment')

Action 函数接收一个与 store 实例(不是 store 实例自身)具有雷同要领和属性的 context(context.state/context.getters/context.commit)对象,也可以应用参数组织。

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
  • 一样支撑载荷和对象体式格局
// 以载荷情势分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象情势分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
  • mapActions 辅佐函数将组件的 methods 映照为 store.dispatch 挪用
import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映照为 `this.$store.dispatch('increment')`

      // `mapActions` 也支撑载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映照为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映照为 `this.$store.dispatch('increment')`
    })
  }
}
  • Promise
actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  },
  //挪用其他action
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}
store.dispatch('actionA').then(() => {
  // ...
})
  • async / await
// 假定 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 守候 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

Modules

将store分割成模块,每一个模块具有自身的 state、mutation、action、getter。

  • 猎取根节点状况rootState
actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
}
getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
}
  • 定名空间:一切 getter、action 及 mutation 都邑自动依据模块注册的门路调解定名
 modules: {
    account: {
      namespaced: true,

      // 模块内容(module assets)
      state: {}, // 模块内的状况已是嵌套的了,应用 `namespaced` 属性不会对其发生影响
      getters: {},
      actions: {},
      mutations: {}
    }
}
  • 接见全局state 和 getter
getters: {
  // 在这个模块的 getter 中,`getters` 被部分化了
  // 你可以应用 getter 的第四个参数来挪用 `rootGetters`
  someGetter (state, getters, rootState, rootGetters) {}
}
actions: {
    // 在这个模块中, dispatch 和 commit 也被部分化了
    // 他们可以接收 `root` 属性以接见根 dispatch 或 commit
    someAction ({ dispatch, commit, getters, rootGetters }) {}
}

带定名空间的绑定函数

  • mapState, mapGetters, mapActions 和 mapMutations的第一个参数接收模块的空间称号字符串
computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo',
    'bar'
  ])
}
  • createNamespacedHelpers建立
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

模块动态注册store.registerModule

// 注册模块 `myModule`
store.registerModule('myModule', {
  // ...
})
// 注册嵌套模块 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

应用store.unregisterModule(moduleName) 来动态卸载模块

15.自定义指令

在 Vue2.0 中,代码复用和笼统的重要情势是组件。但是,有的状况下,你依旧需要对一般 DOM 元素举行底层操纵,这时刻就会用到自定义指令

建立Vue的自定义指令的这五个钩子函数都是可选的,不肯定要悉数涌现。而这个中bind和update两个钩子函数是最有效的。在实际应用的时刻,我们应当依据需求做差异的挑选。比方在适当的时候经由历程bind钩子函数去初始化实例,update钩子函数去做对应的参数更新和应用unbind钩子函数去开释实例资本占用等。

bind(el, binding, vnode)
inserted(el, binding, vnode)
update(el, binding, vnode, oldVnode)
componentUpdated(el, binding, vnode, oldVnode)
unbind(el, binding, vnode)

《VUE2.0进修笔记》

钩子函数参数

指令钩子函数会被传入以下参数:

el:指令所绑定的元素,可以用来直接操纵DOM
binding:一个对象,这个对象包括一些属性,稍后列出每一个属性的寄义
vnode:Vue编译天生的假造节点。有关于VNode更多的材料,可以浏览VNode相干的API
oldVnode:上一个假造节点,仅在update和componentUpdated两个钩子函数中可用

binding参数是一个对象,其包括以下一些属性:

name:指令名,不包括v-前缀
value:指令的绑定值,如例v-hello = "1 + 1"中,绑定值为2
oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,不管值是不是转变都可用
expression:字符串情势的指令表达式。比方v-hello = "1 + 1"中,表达式为"1 + 1"
arg:传给指令的参数,可选。比方v-hello:message中,参数为"message"
modifiers:一个包括润饰符的对象。比方v-hello.foo.bar中,润饰符对象为{foo:true, bar:true}

除了 el 以外,别的参数都应当是只读的,切勿举行修正。假如需要在钩子之间同享数据,发起经由历程元素的 dataset 来举行。著作权归作者一切。

函数简写

在许多时刻,你可以想在 bind 和 update 时触发雷同行动,而不关心别的的钩子。比方如许写:

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})

对象字面量

假如指令需要多个值,可以传入一个 JavaScript 对象字面量。记着,指令函数可以接收一切正当的 JavaScript 表达式。

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "hello!"
})

16.编码范例

编码范例

  1. 每一个 Vue 组件(等同于模块)起首)必需专注于处理一个单一的题目,自力的、可复用的、细小的 和 可测试的。
  2. 组件名应当一直是多个单词的,根组件 App 除外,切勿应用保存字;准绳:有意义的,简短,可读性。
  3. 组件的data必需是一个带return的函数
  4. props尽量应用原始范例的数据,且需要指定其范例
  5. 为 v-for 设置键值,防止v-if 和 v-for 同时用在统一个元素上
  6. 为组件款式设置作用域
  7. 组件组织合理,简约,增加name
  8. 郑重应用this.$parent,this.$refs
  9. 单文件组件文件名的大小写(采纳大驼峰),模板中应用连字符kebab-case
  10. 指令缩写

参考材料:
https://pablohpsilva.github.i…
https://vue-loader.vuejs.org/…

    原文作者:BWrong
    原文地址: https://segmentfault.com/a/1190000017840796
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞