Vue.js 2.0 快速上手 - 基础篇

宁波网站建设 | 2016-10-20

Vue 2.0 出来也有一段时间了,作为一个有志向的全面发展好青年,在征服 Vue 1.x,React,React Native 后,为了之后能更快迁移公司的项目到 Vue 2.x,于是决定先看看 Vue 2.0。

鉴于部分读者可能不了解 Vue,先简单看看各种特性。

本文假设你有一定的 HTML 基础,并熟悉一种或以上编程语言(那就能看懂 JS 了)。

模板语法

Vue 提供了一堆数据绑定语法。

Vue 实例

Vue 实例,实则也就是 ViewModel(数据 + 函数),都是通过构造函数 Vue 创建的:

var data = { a: 1 } var vm = new Vue({  el: '#example',  data: data,  created: function () {  // `this` points to the vm instance  console.log('a is: ' + this.a)  } }) vm.$data === data // -> true vm.$el === document.getElementById('example') // -> true // $watch is an instance method vm.$watch('a', function (newVal, oldVal) {  // this callback will be called when `vm.a` changes }) 

Vue 实例都有自己的生命周期,比如 created, mounted, updated 以及 destroyed。所有方法被 called 的时候,this 都指向所在的 Vue 实例。

Lifecycle 图如下:

计算属性和监听器

计算属性

其实就是一个需要计算的 getter:

<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: {  // a computed getter  reversedMessage: function () {  // `this` points to the vm instance  return this.message.split('').reverse().join('')  }  } }) </div> 

和使用 method 的区别在于,计算属性根据它的依赖被缓存,即如果 message 没有被修改,下次 get 不会进行重复计算,而 method 则每次调用都会重新计算。这也意味着如 Date.now() 这样返回的计算属性会永远得不到更新。

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]  }  } } 

如此,当我们调用 vm.fullName = 'MarkZhai' 的时候,firstName 和 lastName 都会被更新。

监听器

Vue 的 watch 也可以用来做类似的事:

<div id="demo">{{ fullName }}div> 
var vm = new Vue({  el: '#demo',  data: {  firstName: 'Foo',  lastName: 'Bar',  fullName: 'Foo Bar'  },  watch: {  firstName: function (val) {  this.fullName = val + ' ' + this.lastName  },  lastName: function (val) {  this.fullName = this.firstName + ' ' + val  }  } }) 

对比一下计算属性版本:

var vm = new Vue({  el: '#demo',  data: {  firstName: 'Foo',  lastName: 'Bar'  },  computed: {  fullName: function () {  return this.firstName + ' ' + this.lastName  }  } }) 

看上去好像简单了很多,那还要 Watcher 干啥呢。。。主要应用场景是异步或耗时操作:

<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js">script> <script src="https://unpkg.com/lodash@4.13.1/lodash.min.js">script> <script> var watchExampleVM = new Vue({  el: '#watch-example',  data: {  question: '',  answer: 'I cannot give you an answer until you ask a question!'  },  watch: {  // whenever question changes, this function will run  question: function (newQuestion) {  this.answer = 'Waiting for you to stop typing...'  this.getAnswer()  }  },  methods: {  // _.debounce is a function provided by lodash to limit how  // often a particularly expensive operation can be run.  // In this case, we want to limit how often we access  // yesno.wtf/api, waiting until the user has completely  // finished typing before making the ajax request. To learn  // more about the _.debounce function (and its cousin  // _.throttle), visit: https://lodash.com/docs#debounce  getAnswer: _.debounce(  function () {  var vm = this  if (this.question.indexOf('?') === -1) {  vm.answer = 'Questions usually contain a question mark. ;-)'  return  }  vm.answer = 'Thinking...'  axios.get('https://yesno.wtf/api')  .then(function (response) {  vm.answer = _.capitalize(response.data.answer)  })  .catch(function (error) {  vm.answer = 'Error! Could not reach the API. ' + error  })  },  // This is the number of milliseconds we wait for the  // user to stop typing.  500  )  } }) script> 

如此,使用 watch 让我们可以进行异步操作(访问 API),限制操作间隔,并设置中间状态直到获得了真正的答案。

除了使用 watch option,也可以用 vm.$watch API。

Class 和 Style 绑定

除了数据绑定,常见的还有 style、class 的绑定(正如很久以前在 JQuery 中常用的)。

对象语法

我们可以传递一个对象给 v-bind:class 来动态切换 classes:

<div class="static"  v-bind:class="{ active: isActive, 'text-danger': hasError }"> div> 

对应的 active 和 text-danger 则通过 data 传递过来。

我们也可直接通过 data 把 class 传递过来

<div v-bind:class="classObject">div> 
data: {  classObject: {  active: true,  'text-danger': false  } } 

当然我们也能使用上面提到的 computed 来进行对应属性,如 active 的计算。

数组语法

可以直接传递一个数组给 v-bind:class:

<div v-bind:class="[activeClass, errorClass]"> 
data: {  activeClass: 'active',  errorClass: 'text-danger' } 

也可以写成

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

绑定内联样式

跟 class 差不多:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">div> 

或者直接绑定到 style:


		
"styleObject">div> data: { styleObject: { color: 'red', fontSize: '13px' } }

类似的,也有数组绑定。

条件绑定

v-if

其实就是个标签啦

<h1 v-if="ok">Yesh1>  <h1 v-if="ok">Yesh1> <h1 v-else>Noh1> 

因为 v-if 必须附加到一个单一 element 上,那如果我们想切换多个元素呢?可以使用 template 元素:

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

v-show

也可以用 v-show 来做条件显示的逻辑,

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

区别在于

所以如果切换得较为频繁可以使用 v-show ,如果在运行时不太会改变则可以使用v-if

列表渲染

v-for

其实就是个循环标签啦:

<ul id="example-2">  <li v-for="(item, index) in items">  {{ parentMessage }} - {{ index }} - {{ item.message }}  li> ul> 

对应的 vm 实例:

var example2 = new Vue({  el: '#example-2',  data: {  parentMessage: 'Parent',  items: [  { message: 'Foo' },  { message: 'Bar' }  ]  } }) 

模板 v-for

v-if 类似,我们也能在 template 上使用 v-for :

<ul>  <template v-for="item in items">  <li>{{ item.msg }}li>  <li class="divider">li>  template> ul> 

对象 v-for

也能使用 v-for 遍历对象的属性:

<ul id="repeat-object" class="demo">  <li v-for="value in object">  {{ value }}  li> ul> 
new Vue({  el: '#repeat-object',  data: {  object: {  FirstName: 'John',  LastName: 'Doe',  Age: 30  }  } }) 

看到 value,那肯定还有 key 了:

<div v-for="(value, key) in object">  {{ key }} : {{ value }} div> 

如果再加上 index:

<div v-for="(value, key, index) in object">  {{ index }}. {{ key }} : {{ value }} div> 

其他还有像是 v-for="n in 10" 这种用法,就不加上例子了。

组件 v-for

input 输出内容到 newTodoText,每次点击 enter 都会触发 addNewTodo,然后添加 item 到 todos,触发新的 li 添加进去:

<div id="todo-list-example">  <input  v-model="newTodoText"  v-on:keyup.enter="addNewTodo"  placeholder="Add a todo"  >  <ul>  <li  is="todo-item"  v-for="(todo, index) in todos"  v-bind:title="todo"  v-on:remove="todos.splice(index, 1)"  >li>  ul> div> 
Vue.component('todo-item', {  template: '\  
		
  • \ {{ title }}\ \
  • \
    ',
    props: ['title'] }) new Vue({ el: '#todo-list-example', data: { newTodoText: '', todos: [ 'Do the dishes', 'Take out the trash', 'Mow the lawn' ] }, methods: { addNewTodo: function () { this.todos.push(this.newTodoText) this.newTodoText = '' } } })

    key

    当 vue 在更新被 v-for 渲染的列表时候,会使用就地 patch 的策略,而不是根据元素改变的顺序。我们可以提供 key 来做这个排序:

    <div v-for="item in items" :key="item.id">   div> 

    如此,item 会根据 id 来做排序。

    数组改变监测

    替换方法(mutation)

    这些方法会改变原来的 array,并自动触发 view 的更新。

    替换 array

    这几个方法会返回新的 array,如:

    example1.items = example1.items.filter(function (item) {  return item.message.match(/Foo/) }) 

    附加说明

    如果

    都是没法触发更新的,需要使用

    Vue.set(example1.items, indexOfItem, newValue)  // Array.prototype.splice` example1.items.splice(indexOfItem, 1, newValue)  example1.items.splice(newLength) 

    过滤/排序

    配合 computed 以及 filter,或者也可以使用 v-for 的条件渲染:

  • for="n in even(numbers)">{{ n }}
  • data: { numbers: [ 1, 2, 3, 4, 5 ] }, methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) } }

    事件处理

    监听事件

    使用 v-on 指令监听 DOM 的各种事件,如:

    <div id="example-1">  <button v-on:click="counter += 1">Add 1button>  <p>The button above has been clicked {{ counter }} times.p> div> 
    var example1 = new Vue({  el: '#example-1',  data: {  counter: 0  } }) 

    除了直接写 JS 语句,也可以直接在 v-on 中调用 methods 中定义的事件,还可以进行传参:

    <div id="example-3">  <button v-on:click="say('hi')">Say hibutton>  <button v-on:click="say('what')">Say whatbutton> div> 
    new Vue({  el: '#example-3',  methods: {  say: function (message) {  alert(message)  }  } }) 

    我们可能也希望直接把 event 给传递到方法中(比如在方法里 preventDefault 或者 stopPropagation),也很 easy,直接使用特殊的 $event 变量就行了。

    事件修饰符

    除了像上面这样,在 method 里面对 event 进行操作,我们还可以使用事件修饰符(Event Modifier):

    使用如:

     <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>   <div v-on:click.self="doThat">...div> 

    Key 修饰符

    通用的有使用 keyCode 的:

    <input v-on:keyup.13="submit"> 

    其他 alias 别名有

    我们也可以自己通过全局的 config 定义其他别名,如:

    // enable v-on:keyup.f1 Vue.config.keyCodes.f1 = 112 

    表单输入绑定

    基本使用

    text

    <input v-model="message" placeholder="edit me"> <p>Message is: {{ message }}p> 

    如此,用户的输入会直接反映到 data 中的 message,然后更新到

    多行的用 textarea 替换 input 就行了。

    Checkbox

    单个的:

    <input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}label> 

    多个的则可以绑到一个 array :

    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jacklabel> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">Johnlabel> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mikelabel> <br> <span>Checked names: {{ checkedNames }}span> 

    Radio

    <input type="radio" id="one" value="One" v-model="picked"> <label for="one">Onelabel> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Twolabel> <br> <span>Picked: {{ picked }}span> 

    Select

    <select v-model="selected">  <option>Aoption>  <option>Boption>  <option>Coption> select> <span>Selected: {{ selected }}span>  Selected: C 

    多选的在 select 后面加个 multiple,然后对应的会绑定到数组。

    还可以结合 v-for 进行动态渲染:

    <select v-model="selected">  <option v-for="option in options" v-bind:value="option.value">  {{ option.text }}  option> select> <span>Selected: {{ selected }}span> 
    new Vue({  el: '...',  data: {  selected: 'A',  options: [  { text: 'One', value: 'A' },  { text: 'Two', value: 'B' },  { text: 'Three', value: 'C' }  ]  } }) 

    值绑定

    默认地,像上面这样,最后 v-model 绑定到的对象,其值会是一个 静态字符串(或者 true/false),有时候我们想要将其值绑定到一个动态属性,就可以使用 v-bind 来达到目的。

    比如对于 input:

    <input  type="checkbox"  v-model="toggle"  v-bind:true-value="a"  v-bind:false-value="b"> 
    // when checked: vm.toggle === vm.a // when unchecked: vm.toggle === vm.b 

    甚至对象:

    <select v-model="selected">    <option v-bind:value="{ number: 123 }">123option> select> 
    // when selected: typeof vm.selected // -> 'object' vm.selected.number // -> 123 

    修饰符

    .lazy

    默认地,v-model 在每次 input 事件后都会同步输入到数据。加上 lazy 修饰符后就会在 change 事件后才同步:

    <input v-model.lazy="msg" > 

    .number

    会自动把输入转为 number:

    <input v-model.number="age" type="number"> 

    这还是挺有用的,因为就算限制了 input 的 type 为 number,元素的 value 仍然会返回 string。

    .trim

    好像不用多说了?大家都懂吧。

    <input v-model.trim="msg"> 

    组件

    现代的前端框架,通常都是组件化的了。整个应用的搭建,其实就是组件的拼接。自然 Vue 也不会忘了这个。

    使用组件

    注册

    注册一个全局组件,只需要 Vue.component(tagName, options) 即可,如:

    Vue.component('my-component', {  // options }) 

    实际渲染出来的 dom 则定义在 template option 中,如:

    // register Vue.component('my-component', {  template: '
    					
    A custom component!
    '
    }) // create a root instance new Vue({ el: '#example' })

    局部注册

    局部注册只需要放在 Vue 实例中:

    var Child = {  template: '
    					
    A custom component!
    '
    } new Vue({ // ... components: { // will only be available in parent's template 'my-component': Child } })

    使用则像:

    <div id="example">  <my-component>my-component> div> 

    Dom 模板解析限制

    当使用 Dom 作为模板(比如使用 el 选项来使用已有内容加载元素),将会受到一些因为 HTML 工作原理而导致的限制,因为 Vue 只能在浏览器解析后才获取模板数据并进行处理。比如

    中将不能出现自定义组件,只能通过 is 特殊属性进行规避。

    可以通过以下方法使用字符串模板,就不会有这些限制:

    上一篇:智能房屋离我们有多远?苹果联手建筑公司将 HomeKit 带进家下一篇:静态、自适应、瀑布流、响应式四种网页布局有什么区别?
    联系电话 400-6065-301

    微信咨询 寒总监