Vue.js最强大的教程当然是官方文档,本文主要简要概述Vue中一些基础核心概念。

关键是自己多看文档!

环境搭建

官方文档提供了多种安装方式。

  1. 直接用<Script>引入
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  1. 使用NPM安装脚手架工具
npm install -g @vue/cli
OR
yarn global add @vue/cli

如果以为网速问题安装失败,可以考虑使用cnpm来进行安装。

在安装成功之后,就可以使用vue命令了。

image.png

此时使用vue -V查看版本号。

如果有上述返回,那么就可以使用vue命令来创建第一个vue项目了。

> vue create vue-project
Vue CLI v4.3.1
┌─────────────────────────────────────────┐
│                                         │
│   New version available 4.3.1 → 4.4.5   │
│    Run npm i -g @vue/cli to update!     │
│                                         │
└─────────────────────────────────────────┘
? Please pick a preset: default (babel, eslint)
? Pick the package manager to use when installing dependencies: NPM
Vue CLI v4.3.1
✨  Creating project in E:\code\vue-****.
�  Initializing git repository...
⚙️  Installing CLI plugins. This might take a while...
...
...
$  Successfully created project vue-learn.
$  Get started with the following commands:

 $ cd vue-learn
 $ npm run serve

按照最后两行给出的命令,即可将该项目启动了。

image.png

在浏览器中访问给出的地址。

localhost:8080用于本地访问,另一个带IP的地址用于局域网内访问。

image.png

浏览器访问得到如上结果,则说明你的第一个vue项目创建成功了。

模板语法

打开之前创建的vue项目,可以看到每一个vue文件中都存在templatescript两个部分。(此处我删除了template中多余的代码,以及style的内容)。

image.png

模板语法最直观的概述其实就是用于template标签中的语法。

  1. 文本绑定

在上述图例中,{{ }}可以实现数据绑定,将data或者props中定义的变量动态绑定到指定位置。

props中是声明变量,指定变量类型。data是一个函数,返回一个对象,其中包含已经完成赋值的变量,如下图(props,data不能重复)。

image.png

浏览器访问效果如下:

image.png

props只是声明了msg的类型为String,为了对HelloWorld组件的msg赋值,可以由该组件的使用者来传入,方式如下图。

image.png

在script中import我们的自定义组件,然后再components中加入该组件。

在使用{{ }}完成绑定后,绑定的文本值发生了变化,插入的内容也会同步变化。 除非你对使用{{ }}插值的标签添加v-once指定,此时绑定内容改变时该标签也不会发生变化。

  1. 原始Html插入

使用{{ }}插值的方式会由vue自动进行转移,插入的HTML文本只会以文本的方式显示,为此,可以使用v-html指令插入HTML节点。

image.png

image.png

  1. 特性

可能你会想到使用{{ }}来绑定标签的id组件或者value等值,不过vue不支持这种方式。

vue提供了使用v-bind:id的方式来绑定id值。

image.png

image.png

  1. 表达式

在模板中,除了直接使用{{ }}来绑定props以及data中的值,vue还支持在{{ }}中使用JavaScript的表达式。

{{ number + 1 }}

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

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

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

计算属性

计算属性的核心在于拥有依赖关系的数据互相监听,当一个值发生改变时就触发其计算属性,来获得其依赖相关的数据值并且更新。

来看一个简单的Demo。

image.png

如上图,我们添加一个动态绑定的msg值,并且在button中添加每次点击加一的效果。

在computed计算属性中定义a方法,并且在a方法中依赖msg的值。

此时当msg发生变化时,依赖它的a方法也会同时调用,更新div中a的值。

image.png

image.pngpng-14

此处计算属性所完成的功能其实由表达式也可以完成,但在实际业务场景中,值的变化可能有更复杂的方式,无法由表达式一行来实现,这就是计算属性的好处了。

类与样式

与上文id绑定相同,想要关联class,style属性,需要使用v-bind,如下图。

image.png

此外还可以使用object对象以及Boolean的方式来实现。

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

结果如下:

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

条件、列表渲染

  1. 条件渲染

vue中条件指令是v-show,当值为true时显示,为false时不会显示。

image.png

查看DOM可以发现,该标签只是添加了display: none;的style样式。

另一种方式是使用v-if,当值为true时渲染,为false时不会渲染。

v-if与v-show不同,v-if为false时该DOM节点根本不会出现。

image.png

image.png

  1. 列表渲染

vue中可以使用v-for指令来进行列表渲染。

举一个简单的Demo。

image.png

在v-for中指定遍历list,每一项为item。

v-bind:key的作用是为了在list发生变化时,根据key得到哪些项是没有发生变化的,从而去重新渲染改变的项,保证性能。

事件

vue中使用v-on来指定事件的处理方法,支持click,reset,input,cancel,change等类型。

一个简单的Demo。

image.png

上图中第一个Button是v-on指定方法的示例,第二个Button则是指定了需要执行的表达式。

对于需要v-on指令监听的事件,需要在methods中对事件方法进行实现。

通常我们需要在事件触发的情况下传递参数给事件处理方法,vue支持内联的方式传递参数。

image.png

image.png

说完参数传递,在开发中还有一个常见的问题就是事件的冒泡反应,vue支持事件修饰符,来处理冒泡等问题。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止单击事件继续传播 -->
<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>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

组件

组件的定义

vue官网文档中给出了一种组件的定义方式。

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

利用Vue实例来定义一个组件,相对比我们之前所写的组件,这种方式复用性并不高,个人推荐之前的写法。

使用一个vue文件来定义组件。

<template>
  <div>
      ....
  </div>
</template>

其核心在于必须有一个template包裹的组件实现,而script等内容可以省略。

template中的标签必须统一由一个标签包裹,也就是一个template下不能出现两个同级的标签。

如果要使用这个组件,就需要在父组件的script中引入该组件,并且在components中声明,具体如下。

image.png

父组件向子组件传值

我们在引用组件时往往需要传入特定的数据,比如说id,title等来展示我们想要的数据,vue支持通过props来对子组件传值。

image.png

子组件向父组件传值

在vue中,数据的流向是由父组件到达子组件的,父组件想要将数据传达到子组件需要在子组件props中声明特定的变量。那么子组件如何将数据传递给父组件呢?

子组件可以使用$emit调用父组件的自定义事件。

image.png

如上图,我们可以在子组件的button的点击事件中添加一个表达式,该表达式调用emit来调用父组件的parentClick自定义事件。

在父组件中,可以使用v-on:parentClick指令(可简写为@parentClick)来指定父组件中调用的方法。

image.png

slot插槽

你可能尝试过在你的父组件引用子组件时,在子组件的闭合标签中添加内容,但是显示结果却没有这部分内容。

image.png

这时就需要引入slot插槽的概念了,这是vue对w3c的Web Components规范草案的实现之一,将slot元素作为承载分发内容的出口。

你可以在子组件中添加slot标签,来承载父组件在引用时闭合标签内插入的值。

image.png

此时<HelloWorld>标签中的hello就会显示在这个slot的位置。

当然子组件中不一定只有一个slot,为了区分<HelloWorld>中插入的多个HTML标签到底放入哪个slot中,你可以给每一个slot添加一个name,并且在插入时的标签上指定slot。

image.png

自定义指令

之前你可能用过很多次v-前缀的vue指令了,比如v-on,v-bind,v-model,v-html,v-for等等。

vue提供了一个directive的接口让用户自己去定义指令。

来看一个简单的Demo。

image.png

这里我使用directive定义了一个叫做antzuhl的指令,并且在button中使用了它。

在定义时directive支持传入多个钩子函数,由于被添加该指令的组件特定条件下触发。

图中我添加了一个inserted的函数,在添加antzuhl指令的标签被插入到DOM后执行。

directive还支持bind,update,componentUpdated,unbind这几个钩子函数。

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

此处较为核心的是bind,inserted,update三个。

钩子函数支持传入参数,主要是el以及binding两个。

el是指令所绑定的元素,可以用来直接操作DOM。

将之前的自定义指令略作修改,打印参数信息。

image.png

image.png

binding是一个对象,包含以下信息:

  • name:指令名,不包括 v- 前缀。
  • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
  • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
  • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
  • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

Vue-Router

VueRouter是Vue官方的路由管理器,也是Vue学习中的核心点。

在Vue项目中安装vue-router。

npm install vue-router

然后需要配置路由信息,此处我们添加一个route.js来保存路由信息。

image.png

首先需要使用Vue的use方法将VueRouter引入,之后创建一个路由表,配置路由和对应页面实例。

实例化路由对象,传入路由表信息(18行)。

最后将该路由对象导出。

在main.js中的Vue全局实例初始化中,我们还需要将路由实例添加。

image.png

这样router就添加完成了,但是每个页面的跳转中我们还需要渲染路由的匹配组件,为此我们可以将它添加在全局的模板HTML中。

在public/index.html中添加router-view标签。

image.png

此时访问浏览器中路由表信息就可以路由到相应页面。

image.png

如果说想要通过点击等事件跳转进行跳转,可以使用$router或者router-link来进行跳转。

下面是page A与B之间使用两种方式互相跳转的示例。

image.png

image.png

效果如下:

image.png

点击按钮跳转到pageB。

image.png

点击按钮跳转到pageA。

Vuex

Vuex是一个官方指定用于Vue.js状态管理的库。

之前我们已经说过父组件向子组件利用props传递数据,以及子组件向父组件通过调用父组件自定义事件传值。

那么组件间如何进行传值呢?

在我们实际开发中,一个大的页面往往会有很多组件共同需要的数据,比如用户信息,总不能每个组件都去请求一遍吧。

这就是vuex可以解决的问题了。

image.png

在上图中,State就是组件所需要的数据所在的地方,Mutations是对State的操作,Actions是响应用户的操作,从而调用Mutations来修改State。

首先在你的项目中引入vuex。

npm install vuex

在你的项目src中添加一个store目录,并且创建一个store.js的文件。

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        count: 1
    },
    mutations: {
        mutationsChange(state) {
            state.count ++
        }
    },
    actions: {
        actionsChange: ({commit}) => {
            commit('mutationsChange')
        }
    }
})
export default store

在main.js中Vue实例化时引入该store实例。

image.png

此处我们定义一个组件,在按下Button时触发click事件,click事件中调用了使用mapActions绑定的action事件。

而在上面store.js中可以看到,actionsChange中使用commit触发了mutations中mutationsChange操作。

在另一个组件中,我们显示在state中定义的count。

image.png

这样就完成了两个组件间数据共享,以及数据操作更新的问题了。