1. VUE完整系统简介

今天开始系统学习vue前端框架. 我是有前端基础的, 刚工做那会, 哪里分那么清楚啊, 先后端我都得作, 因此, css, js, jquery, bootstrap都会点, 还系统学过ext, 哈哈,是否是都不知道是啥, 没事, 都过期了. 如今开始, 学习最流行的Vue, 后端不会页面, 说不过去呀.....php

言归正传, Ready, Go!css

目录

1. 认识Vuejs

2. Vuejs的安装方式

3. Vuejs的初体验-三个案例

4. MVVM模型

5. Vue对象的生命周期

6. Vue源码


一. 认识Vuejs

  1. 为何学习Vuejs

  • 这几年Vue.js成为前端框架中最火的一个。愈来愈多的网站前端开始采用Vue.js开发。前端开发必备技能.
    • Vuejs是开源世界华人的骄傲,其做者是我国尤雨溪。学习门槛低,成本低,可跨设备和多平台开发Vue.js.
    • 前端换工做, 面试必问的框架.

  2. 简单认识一下Vuejs

  • 官网地址: https://cn.vuejs.org/
    • 是一套用于构建用户界面的渐进式框架, 什么是渐进式框架呢?

        渐进式框架是说, vue能够做为应用的一部分嵌入.html

        好比:以前项目使用的是jquery开发的, 项目体量比较大, 如今知道vue使用上,效果上都更方便, 想要替换为vue, 可问题是以前的页面特别多,若是所有替换,工做量太大,那么不要紧, vue容许你部分嵌入, 也就是说原来的页面依然使用jquery, 然后开发的页面使用Vuejs. vue能够做为一部分嵌入到项目中. 后面再逐渐替换.前端

  • 若是是使用vue开发新项目, 那么可使用vue的全家桶. 包括核心库和和生态系统. 好比: Core+Vue Router + Vuex.

  3. Vuejs的核心功能

  • 解耦视图和数据
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟DOM

二. Vuejs安装方式

vuejs的安装有三种方式, vue

  1. CDN引入

  • CDN引入有两个版本: 开发环境和生产环境. 也就是说, 不用本地安装vue, 而是引入CDN中vue的包
<!-- 开发环境 -->
<script src= "https://cdn.jsdelivr.net/npm/vue/dist/vue.js></script>
<!-- 生产环境 -->
<script src= "https://cdn.jsdelivr.net/npm/vue/vue.js></script>
生产环境建议带上版本号, 避免因版本问题产生异常
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

使用这个版本的优势是: 速度快. 缺点也很明显: 那就是每次打开都要去cdn上下载, 浪费时间. 学习不建议使用这种方式java

  2. 下载和引入

    • 这里也有两个版本, 开发环境和生产环境, 在CDN上下载很慢, 那么咱们能够将vue.js下载到本地, 引入到项目中
      开发环境
      https://vuejs.org/js/vue.js

生产环境
https://vuejs.org/js/vue.min.jsnode

开发时可使用开发包, 能够看到源码. 生产环境的包更稳定, 体积也会更小

##   3\. NPM安装管理

   *   在用 Vue 构建大型应用时推荐使用 NPM 安装
    *   vuejs能够和webpack和CLI等模块配合使用
    *   后续学习都是用这种方式操做的.

# 三. Vuejs初体验

##   1\. Hello Vuejs

    咱们学习程序, 经典代码helloworld. 这里说一下开发工具, 开发工具建议使用vscode, 由于里面有不少插件, 可是其余也不是不能够哈

    咱们在感觉vue的时候, 为了简单, 方便, 咱们使用第二种方式, 下载vue.js, 并引入到项目中. 接下来开始操做.

   *   ### 第一步: 先搭建一个简单的项目. 个人项目名称就叫vue-study. 在里面建立一个文件夹js, 项目结构以下:

    ![image](https://upload-images.jianshu.io/upload_images/25734023-7bd9a920afcbafef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

   *   ###  第二步: 而后下载vue.js, 将其放入到js文件夹中

    *   ###  第三步: 写一个html页面, 并引入vue.js.

<html>
<head>
<title>第一个vue程序</title>
<script src="../js/vue.js"></script>
</head>
<body>python

</body>

</html> jquery

咱们看到, 第一步引入了vue.js. 其实这里有个简单的办法, 只须要把项目中js拖进来, 就能够了.引入了vue.js, 那么要如何使用呢? vue.js咱们能够理解为对象. 使用使用new Vue()的方式.

<html>webpack

<head>
    <title>第一个vue程序</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="app">{{message}}</div>
    <script>
        const app = new Vue({
            el: "#app",
            data: {
                message: "hello, 怒放的太阳!"
            }
        });
    </script>
</body>

</html>

如上, 咱们看到了new Vue(), 至关于把这个对象构建了一份. 而后赋值给了一个常量const app. 这里须要说一下, 之前,咱们都是直接使用var, 既能够设置变量也能够设置常量, 但在vue中, 咱们的变量和常量都有本身的声明方式

 > 声明方式:  常量使用const, 变量使用let.

建立vue对象的时候, 传入了一个option, option中有两个元素

> el:全称element, 表示指向的元素.其值使用的是jquery表达式. 该属性决定了这个vue对象挂载到那个元素上, 能够看出, 咱们这里是挂载到了id="app"的元素上
> data: 这个属性用来存储数据, 这些数据能够试试手动写的, 也能够是动态从服务端取的

data: 这个属性用来存储数据, 这些数据能够试试手动写的, 也能够是动态从服务端取的</pre>

data定义数据. 这里须要重点说一下了. vue采用的是VMMV的设计模式, 也就是数据和试图分离. 这里的data指的就是数据. 而id="app"的div是视图. 当页面解析的时候, 解析到script脚本时发现, 咱们已经将div交给vue容器了, 那么, 这时候, vue就会去寻找目标元素是否有待填补的变量. 这里咱们看到<div id="app">{{message}}</div>里面定义了一个变量message, 而这个变量在vue容器中进行了声明, 所以能够进行对应的自动填充. 

         
这里若是暂时不理解, 也不要紧, 先混个眼熟, 后面还有详细讲解

*   ### 第四步: 分析浏览器执行代码的流程

1 <html>
2
3 <head>
4 <title>第一个vue程序</title>
5 <script src="../js/vue.js"></script>
6 </head>
7
8 <body>
9 <div id="app">{{message}}</div>
10 <script>
11 const app = new Vue({
12 el: "#app",
13 data: {
14 message: "hello, 怒放的太阳!"
15 }
16 });
17 </script>
18 </body>
19 </html>

页面渲染, 首先加载1-10行, 显示出对应的html. 执行到第11行的时候, 建立了vue实例, 而且对照html进行解析和修改.

##   2\. Vue列表展现

    
下面来看一个稍微复杂一点的例子---列表展现

    
先来看看效果

![image](https://upload-images.jianshu.io/upload_images/25734023-19a60c9524075cdf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/340)

    
下面思考, 若是咱们使用jquery会如何实现呢? 须要些一个for循环, 而后在里面定义n个li, 而后拼装数据. 很复杂.  然而, 使用vue彻底不须要在js代码中拼装html元素的数据, 下面来看看怎么作

   *   ### 第一步: 新建一个html页面, 命名为02-list.html, 而后引入vue.js

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表页面</title>
<script src="../js/vue.js"></script>
</head>
<body>

</body>
</html>

*   ###  第二步构建vue对象
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        **<script src="../js/vue.js"></script>**
    </head>
    <body>
        **<div id="app">
            <h1>{{title}}</h1>
            <ul>
                <li v-for = "item in languages">{{item}}</li>
            </ul>
        </div>**
        <script>
            **const app = new Vue({
                el: "#app",
                data:{
                    title: "常见的后端编程语言有哪些?",
                    languages: ["python", "go", "java", "net", "php", "c++"]
                }
            });** </script>
    </body>
    </html>
这里指定了当前构建的vue对象挂载在id="app"的元素上. 并填充值title和languages. 和上一个案例不一样, 这里有一个数组元素languages. 那么数组元素应该如何取值呢?

<ul>
<li v-for = "item in languages">{{item}}</li>
</ul>

注意红色粗体部分. 使用了一个vue的指令v-for, 这是表示for循环, 这个第一次见到, 先熟悉一下. 后面还会具体讲. 咱们之前使用jquery会怎么写呢?

<ul>
<li >python</li>
<li >go</li>
<li >java</li>
<li >php</li>
<li >.net</li>
<li >...</li>
</ul>

之前咱们要这么写一大堆, 若是是动态从服务端取数据, 那么还要拼li代码, 很容易出错, 还很费劲. 但使用了vue指令, 咱们发现一句话就搞定了, 这里是否是能够傲娇一下. 怪不得vue能这么流行.

##   3\. 案例:计数器
     
计数器是一个小的综合案例, 经过这个案例来再次感觉一下vue的强大. 咱们先来看一下效果

    ![image](https://upload-images.jianshu.io/upload_images/25734023-cf0799e3021647b8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/240)
    
分析: 这里有一个变量, 两个按钮. 点击+, 数字加1, 点击-, 数字减1\. 下面咱们就来实现这个功能

   *   第一步: 建立一个html文件03-计数器.html 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app"> 当前数字: {{counter}} <br>
<button v-on:click="counter++"> + </button>
<button v-on:click="counter--"> - </button>

</div>
<script>
const app = new Vue({
el: "#app",
data:{
counter: 0 }
});
</script>
</body>
</html>

引入vue.js, 并建立一个Vue对象. 这些以前都说过, 就很少说了. 接下来看看

<button v-on:click="counter++"> + </button>

这是什么意思呢? 这是vue的写法. v-on是vue的指令, 这里先有个印象, 后面会详细讲解. v-on表示要执行一个事件, :click就是具体的事件, 这里是点击事件, 点击后执行什么逻辑呢? 执行counter ++. 是否是很神奇? 也许尚未感受, 那么咱们来看看, 若是是jQuery, 要怎么作吧?

> 1. 给+按钮添加一个点击事件 
> 2. 获取counter计数器对象的值 
> 3. 对counter进行++
> 4. 再讲counter计算后的结果赋值给计数器对象.       

如今感觉到了吧, jquery是命令式编程, 一行命令执行一个语句. 这里要执行好几句话, 而vue一句话就搞定了.    
*   第二步: 这里click事件中就有一句话, counter++, 那么要是有好多逻辑怎么办呢? 那就须要提出来单独处理了.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app"> 当前数字: {{counter}} <br>
<button v-on:click="add"> + </button>
<button v-on:click="sub"> - </button>
</div>
<script>
const app = new Vue({
el: "#app",
data:{
counter: 0 },
methods: {
add: function() {
console.info(**
"add方法被执行")
this.counter ++;
},
sub: function () {
console.info("sub方法被执行")
this.counter --**;
}
}

}); </script>
</body>
</html>

在vue里面,要想增长一个事件, 那就放在methods属性里就能够了. 这里有一点须要注意. 在方法里要对data中的变量执行counter ++, 直接这么写是不行的, 须要加上this.counter++. this表示的是new出来的Vue对象. 有朋友可能就要说了, this在方法里面, 不该该是表示当前方法么?vue作了一层代理, 因此, 这里的this指的是new Vue()对象.  

# 四. Vuejs的MVVM

##   1\. 什么是MVVM
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让咱们将视图 UI 和业务逻辑分开。固然这些事 ViewModel 已经帮咱们作了,它能够取出 Model 的数据同时帮忙处理 View 中因为须要展现内容而涉及的业务逻辑。View绑定到ViewModel,而后执行一些命令在向它请求一个动做。而反过来,ViewModel跟Model通信,告诉它更新来响应UI。这样便使得为应用构建UI很是的容易。

    
MVVM有助于将图形用户界面的开发与业务逻辑或后端逻辑(*数据模型*)的开发分离开来,这是经过置标语言或GUI代码实现的。MVVM的*视图模型*是一个值转换器,这意味着视图模型负责从模型中暴露(转换)数据对象,以便轻松管理和呈现对象。在这方面,视图模型比视图作得更多,而且处理大部分视图的显示逻辑。 视图模型能够实现中介者模式,组织对视图所支持的用例集的后端逻辑的访问。

##   2\. MVVM的优势

MVVM模式和MVC模式同样,主要目的是分离[视图](https://baike.baidu.com/item/%E8%A7%86%E5%9B%BE)(View)和模型(Model),有几大优势

   *   低耦合。视图(View)能够独立于Model变化和修改,一个ViewModel能够绑定到不一样的"View"上,当View变化的时候Model能够不变,当Model变化的时候View也能够不变。
    *   可重用性。你能够把一些视图逻辑放在一个ViewModel里面,让不少view重用这段视图逻辑。
    *   独立开发。开发人员能够专一于业务逻辑和数据的开发(ViewModel),设计人员能够专一于页面设计,使用Expression Blend能够很容易设计界面并生成xaml代码。
    *   可测试。界面素来是比较难于测试的,测试能够针对ViewModel来写。 

##   3. MVVM模式的组成部分

   *   #### 模型
模型是指表明真实状态内容的领域模型(面向对象),或指表明内容的数据访问层(以数据为中心)。

   *   #### 视图
就像在MVC模式中同样,视图是用户在屏幕上看到的结构、布局和外观(UI)。

  *   #### 视图模型 
视图模型*是暴露公共属性和命令的视图的抽象。MVVM没有MVC模式的控制器,也没有MVP模式的presenter,有的是一个*绑定器*。在视图模型中,绑定器在视图和数据绑定器之间进行通讯。

  *   ####  绑定器
声明性数据和命令绑定隐含在MVVM模式中。绑定器使开发人员免于被迫编写样板逻辑来同步视图模型和视图。在微软的堆以外实现时,声明性数据绑定技术的出现是实现该模式的一个关键因素

##   4\. Vue中的VMMV 
下图不只归纳了MVVM模式(Model-View-ViewModel),还描述了在Vue.js中ViewModel是如何和View以及Model进行交互的。    
![image](https://upload-images.jianshu.io/upload_images/25734023-dfcc86e17fa5cd4d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是做用于某一个HTML元素上的,这个元素能够是HTML的body元素,也能够是指定了id的某个元素。

当建立了ViewModel后,双向绑定是如何达成的呢?

    
首先,咱们将上图中的DOM Listeners和Data Bindings看做两个工具,它们是实现双向绑定的关键。 
    
从View侧看,ViewModel中的DOM Listeners工具会帮咱们监测页面上DOM元素的变化,若是有变化,则更改Model中的数据; 
    
从Model侧看,当咱们更新Model中的数据时,Data Bindings工具会帮咱们更新页面中的DOM元素。

    
拿第一个案例来讲

<html>

<head>
    <title>第一个vue程序</title>
    **<script src="../js/vue.js"></script>**
</head>

<body>
    <div id="app">{{message}}</div>
    <script>
        **const app = new Vue({
            el: "#app",
            data: {
                message: "hello, 怒放的太阳!" }
        });** </script>
</body>

</html>

在这里, 定义了一个View, 定义了model, 建立了一个Vue实例(view-model), 它用于链接view和model

在建立Vue实例时,须要传入一个选项对象,选项对象能够包含数据、挂载元素、方法、模生命周期钩子等等。

在这个示例中,选项对象的el属性指向View,el: ‘#app’表示该Vue实例将挂载到`<div id="app">...</div>`这个元素;data属性指向Model,data: { message: "hello, 怒放的太阳" 表示咱们的Model是一个对象。

Vue.js有多种数据绑定的语法,最基础的形式是文本插值,使用一对大括号语法,在运行时{{ message }}会被数据对象的message属性替换,因此页面上会输出”**hello, 怒放的太阳!**”。

# 五. Vue实例的生命周期

每一个 Vue 实例在被建立时都要通过一系列的初始化过程——例如,须要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程当中也会运行一些叫作生命周期钩子的函数,这给了用户在不一样阶段添加本身的代码的机会。

好比 [`created`]钩子能够用来在一个实例被建立以后执行代码:

new Vue({
data: {
a: 1 },
created: function () { // this 指向 vm 实例
console.log('a is: ' + this.a)
}
}) // => "a is: 1"

也有一些其它的钩子,在实例生命周期的不一样阶段被调用,如 [`mounted`]、[`updated`] 和 [`destroyed`]。生命周期钩子的 `this` 上下文指向调用它的 Vue 实例。

 > **注意:**
>
>不要在选项 property 或回调上使用箭头函数,好比 
>  created: () => console.log(this.a) 或 vm.$watch('a', newValue => >this.myMethod())。
>由于箭头函数并无 this,this 会做为变量一直向上级词法做用域查找,直至找>到为止,常常致使 
>Uncaught TypeError: Cannot read property of undefined 或 
>Uncaught TypeError: this.myMethod is not a function 之类的错误。

## 1\. 生命周期图示

下图展现了实例的生命周期。你不须要立马弄明白全部的东西,不过随着你的不断学习和使用,它的参考价值会愈来愈高。 

 ![image](https://upload-images.jianshu.io/upload_images/25734023-e2c967b24c5fb46c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

##  2\. Vue生命周期函数

如上图, 经常使用的生命周期函数有: beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestory, destoryed, 这些钩子函数都是回调函数, 在vue生命周期执行太重,方便用户操做控制的入口

#  六. Vue源码

咱们知道了vue的生命周期了, 接下来看看vue的源码, 对vue的生命周期加深理解

源码下载地址: https://github.com/vuejs/vue

咱们选择一个release版本. 下载代码到本地

![image](https://upload-images.jianshu.io/upload_images/25734023-4141561e4dac5d70.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 下载好之后, 打开项目, 咱们来看看项目结构.

![image](https://upload-images.jianshu.io/upload_images/25734023-11b1fb25e30e0a07.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/640)

刚开始, 咱们不熟悉, 那么先猜想一下, 哪一个是主要文件, 经验告诉咱们, src里面的才是主目录, 在src中和核心目录是core. 

![image](https://upload-images.jianshu.io/upload_images/25734023-8c0f93a7d7f0f346.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/240)

 咱们看到了index.js, 一般一个网站的入口是index.html, 而对应的js脚本就是index.js. 打开index.js

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$***Context', {
get () {
/ istanbul ignore next /
return this.$vnode && this.$vnode.***Context
}
})

// expose FunctionalRenderContext for *** runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})

Vue.version = 'VERSION'

export default Vue

这里面有两句很是重要的话, 第一句

export default Vue

这句话表示export导出Vue, 咱们new的就是这里导出的Vue. 咱们看到index.js中没有主逻辑, 那主逻辑在哪里呢? 在第二句话里面: 

import Vue from './instance/index'

导入了./instance/index中的文件. 咱们来看看这个文件

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the new keyword')
}
this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

首先, 咱们看到定义了一个Vue对象, 在对象里面执行了不少操做, 初始化, 事件监听, 生命周期处理, 渲染等等. 这就是vue的整个流程. 咱们进入到initMixin(Vue)初始化方法里面看一下

/ @flow /

import config from '../config'
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { mark, measure } from '../util/perf'
import { initLifecycle, callHook } from './lifecycle'
import { initProvide, initInjections } from './inject'
import { extend, mergeOptions, formatComponentName } from '../util/index'

let uid = 0

export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++

let startTag, endTag
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
  startTag = `vue-perf-start:${vm._uid}`
  endTag = `vue-perf-end:${vm._uid}`
  mark(startTag)
}

// a flag to avoid this being observed
vm._isVue = true
// merge options
if (options && options._isComponent) {
  // optimize internal component instantiation
  // since dynamic options merging is pretty slow, and none of the
  // internal component options needs special treatment.
  initInternalComponent(vm, options)
} else {
  vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
  )
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
  initProxy(vm)
} else {
  vm._renderProxy = vm
}
// expose real self
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')

......

初始化的时候又作了一系列的操做. 注意在方法建立以前有一个钩子函数callHook(vm, 'beforeCreate'),  方法建立以后, 有一个callHook(vm, 'created')函数, 这里能够和上面的生命周期图对比研究, 就能更加熟悉Vue的声明周期了
相关文章
相关标签/搜索