VUE常用知识点

Vue.js学习总结

2018-10-14  本文已影响41人  酥枫

html:

<div id="app1">
  {{ message }}
</div>

js:

var app=new Vue({
    el:"#app1",
    data:{
        message:'Hello world'
    }
});

上面的代码就相当于把id为app1的div元素和一个Vue实例绑定了起来(通过传入Vue的对象的el属性来和html元素绑定)。这时候Vue将数据和DOM建立了关联,是响应式的,比如可以通过打开页面之后打开页面的控制台,手动修改app1.message就可以看到页面上自动更新了。

上面html中的这种绑定方式是使用“Mustache”语法 (双大括号) 的文本插值(Mustache就是胡子的意思)

html:

<div id="app2">
  <span v-bind:title="message">
    鼠标悬停几秒钟查看此处动态绑定的提示信息!
  </span>
</div>

js:

var app2 = new Vue({
  el: '#app2',
  data: {
    message: 'This is a message'
  }
});

这样当鼠标悬停在span元素上时,就会看到这段message。在控制台中修改app2.message之后也会立刻在DOM上反映出来。

var vm = new Vue({
  el: '#some-id',
  data: {
    message: 'This is a message'
  }
});
var obj = {
    el: '#some-id',
    data: {
        message: 'This is a message'
    }
}
var vm = new Vue(obj);

上面两种方式均可,不过若是第二种方式,需要对象中的属性名(key)与标准的选项对象中的属性名一样,即名字必须为eldatamethods等。

上面这些属性,都会被初始化为Vue实例的属性,并且是绑定的是响应式的,即:

// 我们的数据对象
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 中存在的属性才是响应式的。也就是说如果你添加一个新的属性,比如:

vm.b = 'hi'

那么对 b 的改动将不会触发任何视图的更新。如果你知道你会在晚些时候需要一个属性,但是一开始它为空或不存在,那么你仅需要设置一些初始值,如:

data: {
  newTodoText: '',
  visitCount: 0,
  hideCompletedTodos: false,
  todos: [],
  error: null
}

在使用Object.freeze()冻结传入的选项对象之后,Vue的响应系统无法再追踪变化。

当然,如果要想访问选项对象的属性,Vue提供了前缀$

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` 改变后调用
})

html:

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id"></div>

这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效:

html:

<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

上面的指令中,v-bindv-on可以被简写,如下:

html:

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

html:

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>

js:

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

运行结果为:

Original message: "Hello"

Computed reversed message: "olleH"

计算属性也可以用vm.reversedMessagge来访问,并且它的值始终依赖于vm.message,后者改变前者也响应式地改变。

使用计算属性的地方也可以通过调用方法来实现,例如:

html:

<p>Reversed message: "{{ reversedMessage() }}"</p>

js:

methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

计算属性处理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]
    }
  }
}
// ...
new Vue({
    el:'#id',
    data:{
        str:'some message'
    },
    watch:{
        str:function(oldStr,newStr){
            //...
        }
    }
});

html:

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

js:

data: {
  isActive: false,
  hasError: true
}

在上面的例子中,activetext-danger这两个class是否存在取决于对应的Vue实例中的属性isActivehasError的真值,同时在Vue中动态的class可以和普通的class并存,所以前面可以还有一个class,所以上面的渲染结果就是:

html:

<div class="static text-danger"></div>

class绑定的数据对象不一定非要内联在模板中,也可以直接就是一个对象,还可以是一个计算属性:

html:

<div v-bind:class="classObject"></div>

js:

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

除此之外,还可以是一个数组(甚至数组中还可以内嵌对象模板):

html:

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

js:

data: {
  isActive: true,
  errorClass: 'text-danger'
}

渲染为:

html:

<div class="active text-danger"></div>

如果是在自定义组件上,这些类会被添加到该组件的根元素上,这个元素上已经存在的类不会被覆盖:
js:

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

html:

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

如果isActive的真值为真,则最终被渲染为:

html:

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

html:

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

js:

data: {
  activeColor: 'red',
  fontSize: 30
}

或者直接绑定到一个样式对象通常更好,这会让模板更清晰:

html:

<div v-bind:style="styleObject"></div>

js:

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

当然,也可以绑定到一个数组,数组的元素为多个样式对象。

html:

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

html:

<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属性来表示这两个元素是完全独立的:

html:

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

当然了,上面的label还是复用了,因为没有给它添加key属性。

v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换。

一般来说,v-if有更高的切换开销,而v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show 较好;如果在运行时条件很少改变,则使用v-if较好。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件<blog-post-row>会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的is特性给了我们一个变通的办法:

<table>
  <tr is="blog-post-row"></tr>
</table>
上一篇下一篇

猜你喜欢

热点阅读