VueJS - Getting Started
文章目录

VueJS

创建实例

1
2
3
4
5
var vm = new Vue({
  el: '#abc',  //所绑定的元素
  data: data,  //所绑定的元素的数据
  created: function({...} //生命周期方法
})

上方放出了几个内置的 Attr 的显示方式.

几个要点:

  1. 调用内置 Attr 的时候需要在前面加上 $
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        var data = { a1 }
        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` 改变后调用
        })
  2. 给生命周期添加钩子函数的时候尽可能不要使用箭头函数, 因为 Vue 需要改变 this 的指向

生命周期

Vue 实例生命周期

模板语法

插值/篡改 Interpolations

1
<span>Message: {{ msg }}</span>

很简单, data.msg 会被显示在这里, 并且可以通过 obj.message 或者 obj.$data.message 进行访问和修改

还有一种一次性插值的方法, 随后这个节点上面的数据就不会被修改了:

1
<span v-once>这个将不会改变: {{ msg }}</span>

Pure HTML 渲染

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

1
2
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

上方第 1 段直接显示了 HTML 代码, 第 2 段对 HTML 进行了解析

直接渲染 HTML 要注意 XSS 攻击的危险

HTML Attributes

可以使用 v-bind 来设置动态的 HTML Attribute

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

但是有一些差异, 比如:

1
<button v-bind:disabled="isButtonDisabled">Button</button>

注意在 HTML 里面直接给 DOM 添加 disabled= 任何值都会禁用这个元素

但是如果给 v-bind:disabled 赋值 false 或者一切可以转换成 false 的值, 那么 disabled 这个 attr 会完全不起作用(渲染后根本就不出现)

Mustache 语法里面使用 JS 表达式

双大括号里面只允许包含单个表达式, 例如下面的例子不会生效:

1
2
3
4
5
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
 
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

指令 Directives

指令里面应该也是包含一个表达式, 这是一个简单的例子:

1
<p v-if="seen">Now you see me</p>

参数 Arguments

1
<a v-bind:href="url"> ... </a>

这里的 href 其实是 v-bind 的参数, 这个操作会修改 当前 link 的指向.

以及:

1
<a v-on:click="doSomething"> ... </a>

这里的 v-on 是 DOM 事件监听函数, 上方就直接监听 click 事件并执行 doSomething 方法

动态参数 Dynamic Arguments

V2.6.0 开始可以使用这个功能

1
2
<a v-bind:[attributeName]="url"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>

方括号里面是一个表达式。

但是这个表达是有一些约束,比如空格和引号会受到限制:

1
2
<!-- 这会触发一个编译警告,这一段代码是无效的 -->
<a v-bind:['foo' + bar]="value"> ... </a>

另外在渲染之后一些大写的测姓名全部会转变成小写:

1
2
<!-- 在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]` -->
<a v-bind:[someAttr]="value"> ... </a>

修饰符 Modifiers

这个随后会有详细的说明

例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

1
<form v-on:submit.prevent="onSubmit">...</form>

计算属性 Computed Properties and Watchers

有些时候我们需要给 data 里面的数据进行一系列运算:

1
2
3
<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

这时候就可以用一个 Computed Properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
 
<script>
  var vm = new Vue({
    el: '#example',
    data: {
      message: 'Hello'
    },
    computed: {
      // 计算属性的 getter
      reversedMessage: function () {
        // `this` 指向 vm 实例
        return this.message.split('').reverse().join('')
      }
    }
  })
</script>

随后只要改变 message , reversedMessage 就会跟着改变了

关于 Computed Properties VS function

我们可以使用 computed properties 也可以建立一个 method 来实现一些方法.

1
2
3
4
5
6
7
<p>Reversed message: "{{ reversedMessage() }}"</p>
 
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

功能是完全相同的, 唯一的区别是: computed properties are cached based on their reactive dependencies

简单来说就是仅仅当依赖改变的时候 reversedMessage 才会重新求值, 否则一直都是之前保存的值

同时一些固定值的 computed properties 永远都不会再次更新:

1
2
3
4
5
computed: {
  now: function ({
    return Date.now() // Date.now() 并不是依赖的值
  }
}

而如果上面这个写成函数的话就每次都会求值

另外, 有时候我们也会用 watched properties 来代替 computed properties, 但是还是建议使用 computed properties

Class & Styles Binding

Class 的绑定

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

对应的 value 是一个 Obj, 如果赋给这样的值:

1
2
3
4
data: {
  isActive: true,
  hasError: false
}

那么就会渲染成:

1
<div class="static active"></div>

另外如果将 hasError 改为 true:

1
2
3
4
data: {
  isActive: true,
  hasError: true // 这里变化了
}

class 列表将变为 "static active text-danger"

另外这里的 value 也可以不直接写出来:

1
<div v-bind:class="classObject"></div>
1
2
3
4
5
6
data: {
  classObject: {
    active: true,
    'text-danger'false
  }
}

传一个数组也可以:

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

关于组件上面的类, 如果你声明了这个组件:

1
2
3
Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})

然后在使用它的时候添加一些 class:

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

HTML 将被渲染为:

1
<p class="foo bar baz boo">Hi</p>

对于带数据绑定 class 也同样适用:

1
<my-component v-bind:class="{ active: isActive }"></my-component>

isActive 为 truthy[1] 时,HTML 将被渲染成为:

1
<p class="foo bar active">Hi</p>

即: 当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面。这个元素上已经存在的类不会被覆盖。

Style 的绑定

和 React 一样, 没啥好说的

1
<div v-bind:style="styleObject"></div>
1
2
3
4
5
6
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

Conditional Rendering 条件渲染

一段神奇的代码:

1
2
3
4
5
6
7
8
9
10
11
12
<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>

这些条件渲染的 tag 必须按照语法来使用

另外可以进行模块化渲染管理:

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

资源复用以及 key 参数的使用 Controlling Reusable Elements with key

Vue 会极大地复用现有的元素

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可:

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

现在,每次切换时,输入框都将被重新渲染。

v-show 以及 v-if 的性能

另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:

1
<h1 v-show="ok">Hello!</h1>
  • v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
  • v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
  • 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
  • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

列表渲染

v-for 循环语法

用法其实很简单就是 item in item 的格式, 另外还可以扩展出第二个参数

数组循环

1
2
3
4
5
<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
1
2
3
4
5
6
7
8
9
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

对象循环

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

反正就是很简单

循环中使用 key 来标注不同元素

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

和 react 一样, 没什么好说的

数组更新检测

一些数组方法会对当前数组进行变化, 这些就会直接反映到渲染中:

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

但是一些方法会新生成数组.

例如:filter()concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:

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

就是赋值给原来的地址上面的数组

注意事项

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength
使用索引设置数组项
1
2
3
4
5
6
7
var vm = new Vue({
  data: {
    items: ['a''b''c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

上面这些个操作不会改变渲染的情况

解决方法:

1
2
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
1
2
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

你也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

1
vm.$set(vm.items, indexOfItem, newValue)
修改数组的长度

解决方法:

1
vm.items.splice(newLength)

对象修改

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

解决方法:

1
2
3
4
5
6
7
8
var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
&nbsp;&nbsp;&nbsp;&nbsp;  //这里我想添加个 age: 27
    }
  }
})

你可以添加一个新的 age 属性到嵌套的 userProfile 对象:

1
Vue.set(vm.userProfile, 'age', 27)

你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名:

1
vm.$set(vm.userProfile, 'age', 27)

有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:

1
2
3
4
Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

你应该这样做:

1
2
3
4
5
//区别就是 Assign 到了一个 新的 空 obj 上面
vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

渲染实例

渲染/排序

使用 computed 方法的情况:

1
<li v-for="n in evenNumbers">{{ n }}</li>
1
2
3
4
5
6
7
8
9
10
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

以及 method 方法的实现:

1
<li v-for="n in even(numbers)">{{ n }}</li>
1
2
3
4
5
6
7
8
9
10
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}