Vue.js 2.0 快速上手 - 基础篇 - 知乎专栏 ·「魔都三帅」-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

Vue.js 2.0 快速上手 - 基础篇 - 知乎专栏 ·「魔都三帅」

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

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

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

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

模板语法

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

  • {{ text }} 文本插值
  • HTML 输出
  • v-bind HTML 属性插值。如
  • JavaScript 表达式。直接在 mustache、属性插值里面使用各种表达式(加减乘除、三元运算、方法调用等)。
  • 过滤器(有点类似 Shell 命令中的管道,可以定义过滤器来对原始值进行变化)。
  • 指令。之前提到的 v-bind 也是一种指定,其他包括 v-on: 系列(dom 事件的监听)、v-for、v-model等。

Vue 实例

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


var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data,
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})
vm.$data === data // -> true
vm.$el === document.getElementById('example') // -> true
// $watch 是一个实例方法
vm.$watch('a', function (newVal, oldVal) {
  // 这个回调会在 `vm.a` 改变的时候触发
})

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

计算属性和监听器

计算属性

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


riginal message: "{{ message }}"


  
Computed reversed message: "{{ reversedMessage }}"



var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 一个 computed getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

和使用 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 也可以用来做类似的事:


{{ fullName }}

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 干啥呢。。。主要应用场景是异步或耗时操作:

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

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

Class 和 Style 绑定

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

对象语法

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


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

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


data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

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

数组语法

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



data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

绑定内联样式

跟 class 差不多:

或者直接绑定到 style:


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

类似的,也有数组绑定。

条件绑定

v-if

其实就是个标签啦


Yes


Yes

No


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


v-show

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


Hello!


区别在于

  • v-show 不支持 template 和 v-else
  • v-if 是 lazy 的,不会渲染没有走到的条件。而 v-show 只是简单的基于 CSS 的切换。所以 v-show 的初始 render 代价较高。
  • 由于 v-if 是真实的渲染,切换后原来的 dom 会被 destroyed,而新的 dom 会被重新创建。所以切换代价更高。

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

列表渲染

v-for

其实就是个循环标签啦:


    {{ parentMessage }} - {{ index }} - {{ item.message }}

对应的 vm 实例:

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

模板 v-for

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

对象 v-for

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


  {{ value }}
  

new Vue({
  el: '#repeat-object',
  data: {
    object: {
      FirstName: 'John',
      LastName: 'Doe',
      Age: 30
    }
  }
})


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


  {{ key }} : {{ value }}


如果再加上 index:


 {{ index }}. {{ key }} : {{ value }}


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

组件 v-for

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


 
Add a todo



  


Vue.component('todo-item', {
  template: '\
\
      {{ title }}\
      X\
    
\
  ',
  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 来做这个排序:


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

数组改变监测

替换方法(mutation)

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

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

替换 array

  • filter()
  • concat()
  • slice()

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


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

附加说明

如果

  • 直接 set array 的值,如 vm.items[indexOfItem] = newValue
  • 修改 array 的长度,如 vm.items.length = newLength

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


Vue.set(example1.items, indexOfItem, newValue)

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

example1.items.splice(newLength)

过滤/排序

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


{{ n }}


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

事件处理

监听事件

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


Add 1
The button above has been clicked {{ counter }} times.



var example1 = new Vue({
  el: '#example-1',
  data: {
    counter: 0
  }
})


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



  Say hi
  Say what

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


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

事件修饰符

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

  • .stop
  • .prevent
  • .capture
  • .self

使用如:




 ...



 ...


Key 修饰符

通用的有使用 keyCode 的:

其他 alias 别名有

  • enter
  • tab
  • delete (captures both “Delete” and “Backspace” keys)
  • esc
  • space
  • up
  • down
  • left
  • right

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


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


表单输入绑定

基本使用

text



edit me

Message is: {{ message }}



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

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

Checkbox

单个的:



{{ checked }}


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



Jack

John

Mike


Checked names: {{ checkedNames }}

Radio



One



Two


Picked: {{ picked }}


Select



Selected: {{ selected }}
 Selected: C


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

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


值绑定

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

比如对于 input:



// when checked:
vm.toggle === vm.a
// when unchecked:
vm.toggle === vm.b


甚至对象:



// when selected:
typeof vm.selected // -> 'object'
vm.selected.number // -> 123


修饰符

.lazy

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

.number

会自动把输入转为 number:

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

.trim

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

组件

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

使用组件

注册

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


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


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


// 注册
Vue.component('my-component', {
  template: '

A custom component!

'
})
// 创建一个根实例
new Vue({
  el: '#example'
})



局部注册

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


var Child = {
  template: '
A custom component!

'
}
new Vue({
  // ...
  components: {
    //  只在父亲的模板里可用
    'my-component': Child
  }
})



Dom 模板解析限制

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

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

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


Vue.component('hello-world', {
  template: '#hello-world-template'
})


  • 在极小的应用或者大型模板的 demo 的时候可能会有用,其他情况下应该尽量避免。因为这样会把它和其他模板定义给隔离开。

    v-once 定义简单的静态组件

    在 Vue 里面渲染纯净的 HTML 元素是很快的,但有时候你可能需要一个包含了很多静态内容的组件。这种情况下,你可以通过在根元素加上 v-once 指令确保它只被评估了一次然后就被缓存下来了,像是这样:

    Vue 1.x TO 2.0

    通过使用 vue-migration-helper 可以快速扫出需要替换的代码。

    主要有以下几类:

    • 官方依赖,比如 vue-resource、vue-router(这个升级完接口也改了不少,迁移向导)、vue-loader、vue-hot-reload-api、vue-invalidate(还在升级中)等。
    • 第三方库。
    • UI组件库,比如 vux(目前计划是11月发布适配 2.0 的版本)、饿了么前端提供的那些(并没有给出更新计划)。
    • 组件间通讯,不能再使用 dispatch,而需要使用全局 eventbus 或者 vuex。
    • 各种 API 废弃,见 issue 2873,像是 attached、activated 这些生命周期 API 都被干掉了。

    具体一点的话,像是

    index

    $index 现在必须使用 index 了(在 v-for 中显示声明)

    filters

    不能像以前那样到处用了,只在 {{ }} 中生效,转而用计算属性或者方法吧。

    transition

    transition 属性被废弃了。可以看看新的 Transitions 文档

    vue router

    加了全局和离开当前页面的钩子,router-link,router data,等等。

    等等等等,要升级还是挺痛苦的。啊,对了 vuex 也升级到 2.0 了。更像 redux 了。心情很复杂

    尾声

    差不多也就是这样了。如果你是一个有一定经验并懂得基本 HTML 和 CSS 的高级工程师,我相信几天你就能看完并上手它了,毕竟对比 React 那一整套东西,还是相对简单的。


  • Vue.component('terms-of-service', {
      template: '\
    \
    Terms of Service
    
    \
          ... 很多静态内容 ...\
        
    
    \
      '
    })




原文发布时间为:2016年11月10日
原文作者:掘金
本文来源:掘金 如需转载请联系原作者

 






版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章