Vue 相关知识整理

2018/1/24 posted in  Vue

简单介绍我所知道的关于Vue这款前端框架相关的知识点。

介绍

Vue (读音 /vjuː/,类似于 view) 由大神尤雨溪开发的一套用于构建用户界面的渐进式框架。使用Vue开发最好了解一下HTML、CSS和Javascript的中级知识。

使用 Vue 就不要再想着怎么操作DOM了,要想着如何操作数据!!

兼容性

Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。

开发调试工具

使用Vue时,可以在浏览器上面装上 Vue Devtools,可以更好的调试。

其他模板引擎

模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。百度百科

Vue 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进DOM的框架。除此之外还有一些其他的模板渲染库(下面列的是我知道的,其他的欢迎补充):

  • art-template 轻量的模板渲染引擎
  • laytpl layui 前端框架里的模板引擎模块

Vue 和 Jquery 的区别

这两个最主要的区别就是,Vue是操作数据改变DOM,而Jquery是需要去直接操作DOM。

下面两个例子,展示了Jquery和Vue的区别:
todo_jq
todo_vue

这只是一个简单的示例,可以想象如果是操作比较复杂的DOM,哪种方式更方便。少了对DOM的操作,开发、维护的效率都会明显提高。

安装

Vue 的使用方式由两种:

  • 直接通过<script>的方式引入到HTML上,这种方式创建组件比较麻烦,比较适合小型的项目开发。

  • 另外一种就是通过 npm 安装,适合大中型项目开发,可以很好的利用 webpack 等一些模块打包工具,可以创建单文件组件,方便重复利用。允许我们使用小型、独立和通常可复用的组件构建大型应用。

一、 通过JS文件直接引入

这种方式用来写一个页面的小功能来说,还是很方便。之前我自己写的五子棋的小游戏就是通过这种方式来制作的。

创建一个 .html 文件,引入 Vue

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
  {{ message }}
</div>

声明Vue

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Word!'
  }
});

显示出来的源码

<div id="app">
  Hello Word!
</div>

二、npm 的方式

这种方式主要用来创建中大型单页应用,不然太浪费了。

这种方式需要安装 nodejs,和传统前端有很大的区别,需要学习很多新的知识。新手建议使用上一种方式。

相关的工具:

  • nodejs
  • webpack 打包工具
  • vuex 状态管理
  • vue-cli Vue 官方提供的构建工具
  • vue-router 创建单页应用必须的前端路由
  • axios 基于Promise 为基础的HTTP客户端,用来发送请求,异步获取数据
  • typescript Vue最新的版本开始都将支持TypeScript

通过 npm 命令安装

npm install vue

数据绑定

  • Mustache(插值语法),就是{{}}语法
  • 数据都是从数据对象 data 中获取
  • 数据对象的属性值发生了改变,插值处的内容也会更新
  • {{}} 中只能出现 JavaScript表达式
  • Mustache 语法不能作用在 HTML 元素的属性上,属性值需要用 v-bind 指令
  • 双打括号会将数据解释为普通的文本,而非HTML代码,可以用 v-html 指令输出HTML代码
<h1>{{ message }}</h1>
<h2>{{ list[0] }}</h2>
<li v-for="item in list">{{ item }}</li>
<div v-html="html"></div>
<div v-bind:id="id"></div>

双向数据绑定

通过 v-model 指令将表单输入与Vue实例的data数据绑定到一起,彼此之间互相影响

  • 数据的改变会引起DOM的改变
  • 表单输入会改变数据
<div id="app-6">
  <p>{{ message }}</p>
  <input v-model="message">
</div>
var app6 = new Vue({
  el: '#app-6',
  data: {
    message: 'Hello Vue!'
  }
});

原理:

注意点

  • 只有当实例被创建时 data 中存在的属性才是响应式的
  • Vue.set(object,key,value) 方法可以动态将响应属性添加到Vue实例上

    Vue.set(vm.someObject,'b',2);
    

    也可以使用 vm.$set 实例方法

    this.set(this.someObject,'b',2);
    
  • 另外数组如果要改变某一项的值,也需要用 this.set 方法

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

    也可以用数组的 splice 方法

    example1.items.splice(indexOfItem, 1, newValue)
    
  • 对象属性的添加或者删除

    添加单个属性

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

    添加多个属性

    this.userProfile = Object.assign({}, this.userProfile, {
        age: 27,
        favoriteColor: 'Vue Green'
    });
    

异步DOM更新

  • Vue 通过异步、队列执行 DOM 更新
  • 可以去除重复数据,避免不必要的计算和DOM操作
  • 在修改数据之后,立即使用 Vue.nextTick(callback) ,DOM更新完成之后就会调用
<div id="example">{{message}}</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: '123'
  }
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
})

指令

  • v-text 更新元素的 textContent

    <span v-text="msg"></span>
    <!-- 和下面的一样 -->
    <span>{{msg}}</span>
    
  • v-html 更新元素的 innerHTML ,注意:内容按普通的 HTML 插入

    <div v-html="html"></div>
    
  • v-show 根据表达式之真假值,切换元素的 display CSS属性

    <div v-show="true"></div>
    
  • v-if 根据表达式的值的真假条件渲染元素。如果需要频繁切换显示的元素,请使用 v-show 指令 #条件渲染

    <div v-show="true"></div>
    
  • v-for 基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression ,为当前遍历的元素提供别名

    <div v-for="(item, index) in items">
        {{ item.text }}
    </div>
    

    v-for 默认行为试着不改变整体,而是替换元素。迫使其重新排序的元素,你需要提供一个 key 的特殊属性:

    <div v-for="item in items" :key="item.id">
        {{ item.text }}
    </div>
    
  • v-on 绑定事件 #事件处理器

    <!-- 方法处理器 -->
    <button v-on:click="doThis"></button>
    
    <!-- 内联语句 -->
    <button v-on:click="doThat('hello', $event)"></button>
    
    <!-- 缩写 -->
    <button @click="doThis"></button>
    

    事件修饰符,修饰事件的行为:

    • 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 } 模式添加侦听器
    <!-- 停止冒泡 -->
    <button @click.stop="doThis"></button>
    
    <!-- 阻止默认行为 -->
    <button @click.prevent="doThis"></button>
    
  • v-bind 动态地绑定一个或多个特性,或一个组件 prop 到表达式 #Class 与 Style 绑定 #组件 - Props

    <!-- 绑定一个属性 -->
    <img v-bind:src="imageSrc">
    
    <!-- 缩写 -->
    <img :src="imageSrc">
    
    <!-- 内联字符串拼接 -->
    <img :src="'/path/to/images/' + fileName">
    
  • v-model 用于表单控件的数据绑定 #表单输入绑定

    <input v-model="message" placeholder="edit me">
    <p>Message is: {{ message }}</p>
    
  • 性能优化

    • v-pre 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

      <span v-pre>{{ this will not be compiled }}</span>
      
    • v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。 #组件 - 对低开销的静态组件使用 v-once

      <!-- 单个元素 -->
      <span v-once>This will never change: {{msg}}</span>
      <!-- 有子元素 -->
      <div v-once>
          <h1>comment</h1>
          <p>{{msg}}</p>
      </div>
      <!-- 组件 -->
      <my-component v-once :comment="msg"></my-component>
      <!-- `v-for` 指令-->
      <ul>
          <li v-for="i in list" v-once>{{i}}</li>
      </ul>
      

计算属性

  • 计算属性是基于它们的依赖进行缓存的,只有在它的依赖发生改变时才会重新求值
  • computed中的属性不能与data中的属性同名,否则会报错
<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('')
    }
  }
});

监视数据变化

  • 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
    }
  }
})

生命周期钩子

  • beforeCreate 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

  • created 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

  • beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。

  • mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。 注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted

  • beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。

  • updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick 替换掉 updated

  • activated keep-alive 组件激活时调用。

  • deactivated keep-alive 组件停用时调用

  • beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。

  • destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

组件 #

组件是 Vue.js 最强大的功能之一,允许我们使用小型、独立和通常可复用的组件构建大型应用。这里还是建议,如果要用组件,还是用第二种构建方式,那样开发起来比较舒服,可以创建 .vue后缀的单文件组件。

注册

全局组件

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

局部组件

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

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

单文件组件
单文件组件data属性必须是一个函数

<!-- .vue后缀文件 -->
<template>
  <div>This will be pre-compiled</div>
</template>

<script>
    import ElseComponent from './elseComponent.vue' //引用其他单文件组件
    
    export default {
        name:'text',
        props:{},
        data:function(){
            return {}
        }
    }
</script>

通讯

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。

父组件到子组件

  • 通过子组件的 props 属性来下发到子组件中
  • 传递过来的 props 属性的用法与 data 属性的用法相同
  • props 是单向绑定,只能通过父组件传递给子组件,父组件每次更新是,子组件的所有 prop 都会更新为最新值,所以 props 选项属性的值只能读取,不能修改

子组件显式的用 props 选项声明它预期的数据

Vue.component('child', {
  // 声明 props
  props: ['message'],
  // 就像 data 一样,prop 也可以在模板中使用
  // 同样也可以在 vm 实例中通过 this.message 来使用
  template: '<span>{{ message }}</span>'
})

然后在父组件调用时传递数据

<child message="hello!"></child>

如果要修改数据:

  1. 定义一个局部变量,并用 prop 的值初始化它

    props: ['initialCounter'],
    data: function () {
        return { counter: this.initialCounter }
    }
    

子组件到父组件

  • 父组件利用自定义事件传递一个函数给子组件,子组件调用这个函数
<hello @pfn="parentFn"></hello>

<script>
  Vue.component('hello', {
    template: '<button @click="fn">按钮</button>',
    methods: {
      // 子组件:通过$emit调用
      fn() {
        this.$emit('pfn', '这是子组件传递给父组件的数据')
      }
    }
  })
  new Vue({
    methods: {
      // 父组件:提供方法
      parentFn(data) {
        console.log('父组件:', data)
      }
    }
  })
</script>

异步组件

大型应用中,我们需要将应用分为多个小模块,按需从服务器下载,这个时候就要用到 Vue 的异步组件。

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 将组件定义传入 resolve 回调函数
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

推荐配合 webpack的代码分割功能来使用

Vue.component(
  'async-webpack-example',
  // 该 `import` 函数返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

基于Vue开发的组件库

Mint UI
Element
iView

结语

由于我懂的也比较少,所以就写到这里了,其实Vue还有很多要学习的知识,尤其是组件那一块,最完整的学习还是看官网文档。写这篇博文,主要是借鉴了下面文章和官方文档:

vue开发看这篇文章就够了

写这篇博文,是因为最近公司领导要求我来介绍下Vue。但其实我对Vue也只是停留在简单的能用阶段,所以只是对我了解的Vue和一些相关知识简单介绍下。文笔不是很强,有遗漏或错误之处欢迎指出,共同学习、共同进步。

文档信息

  • 版权声明:自由转载-非商用-非衍生-保持署名( 创意共享3.0许可证
  • 邮箱: ntzw.geek@gmail.com
  • 在技术的世界里,需要不断学习、不断进步。对文章内容有任何疑问或异议欢迎来信讨论!