Demo entry 6718264

grsffffgdf

   

Submitted by anonymous on Mar 03, 2018 at 08:51
Language: HTML + Angular2. Code size: 15.4 kB.

##0.目录
[TOC]
#1.简介
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的[渐进式框架][1]{:target="_blank"}。与其它大型框架不同的是,Vue 被设计为可以**自底向上**逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。Vue.js 的目标是通过尽可能简单的 API实现响应的**数据绑定**和组合的**视图组件****PS** Vuejs的作者尤雨溪写过一篇关于新手学习vue路径的文章[Vue 2.0 的建议学习顺序][2]{:target="_blank"}
##1.1 特点
![Vue特点](http://localhost:8080/img/vue/特点.png)

1. 简洁:官方文档很清晰,代码编写风格更加简洁,并且通俗易懂。
2. 高效:异步批处理方式更新DOM[^1]和超快虚拟 DOM。
3. 组件化:用解耦的、可复用的组件组合你的应用程序。Vue通过将页面上某一组件的html、CSS、js代码放入一个.vue的文件中进行管理可以大大提高代码的维护性。
4. 轻量:20kB min+gzip 运行大小
5. 数据驱动:是一个MVVM的前端框架

##1.2 MVVM模式
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素。

```html
<div id="app">
  <input v-model="message">
  <p>消息是: {{ message }}</p>
</div>
<script>
new Vue({
  el: '#app',
  data: {
    message: 'hello world'
  }
});
</script>
```

![Vue模型](http://localhost:8080/img/vue/mvvm.png)
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。

1. 从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
2. 从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。

#2.语法

##2.1VUE实例
每个 Vue 应用程序都是通过 Vue 函数创建出一个新的 Vue 实例开始的:
###创建一个 Vue 实例

```javascript
var vm = new Vue({
})
```
###data
Vue实例的数据都保存在data对象中,Vue将会递归将data的属性转换为getter/setter, 让data数据能够响应变化。

1. 类型是Object或者Function。
2. 如果是组件对象中,data必须是Function类型。

```javascript
// data 对象
var data = { a: 1 }

// 此对象将会添加到 Vue 实例上
var vm = new Vue({
  data: data
})

// 这里引用了同一个对象!
vm.a === data.a // => true

// 设置实例上的属性,也会影响原始数据
vm.a = 2
data.a // => 2

//注册组件使用data函数
Vue.component('component1', {
      template: '<button v-on:click="counter += 1">{{ counter }}</button>',
      // data是一个函数,vue不会报错,但是我们返回给每个组件的实列引用了同一个data对象
      data: function() {
        return data
      }
});
```
如果实例已经创建,那么只有那些 data 中的原本就已经存在的属性,才是响应式的。也就是说,如果在实例创建之后,添加一个新的属性,```vm.b = 'hi'```例如:然后,修改 b 不会触发任何视图更新。

###computed
Vue的计算属性(computed)的属性会自动混入Vue的实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
语法
>{ 键:函数} { \[key: string\]: Function | { get: Function, set: Function } } 当然,可以省略setter,如果省略了setter,那么值就可以是普通函数,但是必须有返回值。

```html
<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>
```
###methods
使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
```javascript
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  methods: {
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
});
```

###watch
Vue 提供了一种更通用的方式watch来观察和响应 Vue 实例上的数据变动:侦听属性。
语法
>{ \[key: string\]: string | Function | Object }

```javascript
var vm = new Vue({
  data: {
    a: 1
  },
  watch: {
    // 监控a变量变化的时候,自动执行此函数
    a: function (val, oldVal) {
      console.log('new: %s, old: %s', val, oldVal)
    }
  }
})
```
###生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数。实例化生命周期 从开始创建,初始化数据,编译模板,挂载Dom->渲染, 更新->重新渲染,销毁等。
![生命周期示意图](http://localhost:8080/img/vue/lifecycle.png)
```
beforeCreate: function() {}  
// 在实例初始化之后, 数据观测 和 event/watcher 事件配置之前被调用。
created: function() {}       
// 实例已经创建完成之后被调用。实例已完成如: 数据观测,属性和方法的计算,watch/event事件回调。
beforeMount: function() {}   
// 在挂载开始之前被调用, 该函数在服务器端渲染期间不会被调用。
mounted: function() {}       
// el被新创建的 vm.$el替换,并挂载到实例上去之后调用该函数,在该函数内可以获取元素。
render: function() {}        
// 页面被渲染时会调用该函数。该函数在mounted之前会被调用。
beforeUpdate: function(){}   
// 数据更新时调用,发生在虚拟Dom重新渲染之前。该函数在服务器端渲染期间不会被调用。
updated: function() {}       
// 由于数据更改导致虚拟DOM重新被渲染会调用。在被渲染后调用该函数。可以或许新的dom元素。该函数在服务器端渲染期间不会被调用。
activated: function() {}     
// keep-alive组件激活时调用 该函数在服务器端渲染期间不会被调用。
deactivated: function(){}    
// keep-alive 组件停用时被调用。该函数在服务器端渲染期间不会被调用。
beforeDestroy: function(){}  
// 实例销毁之前被调用,实例仍然完全可用 该函数在服务器端渲染期间不会被调用。
destroyed: function() {}    
 // Vue 实例销毁后调用,调用后,Vue实例所有东西都会被解绑定,所有的事件监听器会被移除,所有的实例被销毁。
```

```html
<div id='app'>
    <p> {{ number }} </p>
    <input type='text' v-model='number' />
</div>
<script type="text/javascript">
var vm = new Vue({
    el: '#app',
    data: {
        number: 1
    },
    beforeCreate: function() {
        console.log('beforeCreate', this.number);
    },
    created: function() {
        console.log('created', this.number);
    },
    beforeMount: function() {
        console.log('beforeMount:', this.number)
    },
    mounted: function() {
        console.log('mounted', this.number);
    },
    beforeUpdate: function() {
        console.log('beforeUpdate', this.number);
    },
    updated: function() {
        console.log('updated', this.number);
    },
    beforeDestroy: function() {
        console.log('销毁前.....');
    },
    destroyed: function() {
        console.log('已销毁.....');
    }
});
</script>
```
在浏览器控制台看到,第一次页面加载后,打印信息如下
![生命周期测试1](http://localhost:8080/img/vue/lifecycletest1.png)
页面第一次加载后,触发了 beforeCreate,created,beforeMount等生命周期函数,当然 mouted 生命周期在加载完后dom操作也会被触发的。
接着在input输入框 在输入一个2字,控制台打印出如下信息
![生命周期测试2](http://localhost:8080/img/vue/lifecycletest2.png)
可以看到当内容被更新的时候 调用了 beforeUpdate 和 updated 等生命周期函数。
调用如下销毁方法:vm.$destroy() 后,在控制台会打印如下信息:
![生命周期测试3](http://localhost:8080/img/vue/lifecycletest3.png)
###渲染Vue实例
要将Vue实例渲染到HTML页面中,采用Vue实例的$mount()方法,这个方法的名称,意味着渲染实际上是将Vue实例生成的(虚拟)DOM子树,挂接到页面DOM中。```vm.$mount(anchor_element);```Vue.js也提供了一个实例化时的配置项el,来允许我们隐式地启动Vue实例的渲染。el用来声明目标渲染锚点

```javascript
Vue({
  template: '<h1>Hello,Vue.js 2!</h1>',
  el: '#app'
})
```
**工作原理**
如果Vue.js检测到你指定了el配置项,将在内部自动地执行渲染 —— 这时你
不再需要额外调用$mount()方法了,在开始学习时,使用$mount()方法,会让你更多一点理解[Vue.js][4]{:target="_blank"}
的设计思想。
![渲染Vue实例](http://localhost:8080/img/vue/implicit-render.png)
##2.2 指令
Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。
Vue.js提供了一些常用的内置指令,接下来我们将介绍以下几个内置指令:

* v-if/v-else/ v-else-if
* v-show指令
* v-for指令
* v-bind指令
* v-on指令

###v-if指令
v-if是条件渲染指令,它根据表达式的真假来删除和插入元素
语法```v-if="expression"```

```html
<div id="app">
    <h1 v-if="yes">Yes!</h1>
    <h1 v-if="age >= 25">Age: {{ age }}</h1>
</div>
<script>
var vm = new Vue({
    el: '#app',
    data: {
        yes: true,
        age: 28
    }
})
</script>
```

如果想切换多个元素呢?此时可以把一个```<template>```元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染
结果将不包含 ```<template>```元素。

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

###v-else与v-else-if
v-else,v-else-if必须紧跟在带 v-if或者 v-else-if 的元素之后,分别来表示 v-if 的“else 块”和 的“else-if块”
```html
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else>  Not A/B</div>
```
###v-show指令
v-show也是条件渲染指令,和v-if指令不同的是,使用v-show指令的元素始终会被渲染到HTML,它只是简单地为元素设置CSS的style属性。
例子```<h1 v-show="isShow">Hello!</h1>```

###v-for指令
v-for指令基于一个数组渲染一个列表,它和JavaScript的遍历语法相似;v-for指令需要使用```item in items``` 形式的特殊语法,items是源数据数组并且item是数组元素迭代的别名。
```html
<ul id="app">
    <li v-for="(item, index) in items">
        {{ parentMessage }} - {{ index }} - {{ item.message }}
    </li>
</ul>
<script>
var vm = new Vue({
    el: '#app',
    data: {
        parentMessage: 'Parent',
        items: [
            { message: 'Foo' },
            { message: 'Bar' }
        ]
    }
})
</script>
```

###v-bind指令
v-bind指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),例如:v-bind:class
v-bind:argument="expression" 也可以缩写为:argument="expression"
```html
<div id="app">
    <img v-bind:src="url" :title="message" :class="[classA,classB]"/>
</div>
<script>
var vm = new Vue({
    el: '#app',
    data:{
        url: "../img/pg.png",
        title: "this is a Pic",
        classA: 'textColor',
        classB: 'textSize'
    }
})
</script>
```

###v-on指令
v-on指令用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听a元素的点击事件:```<a v-on:click="doSomething">```有两种形式调用方法:绑定一个方法(让事件指向方法的引用),或者使用内联语句。v-on:click也可以缩写为@click="expression"

```html
<div id="app">
    <button v-on:click="counter += 1">Add 1</button>
    <p>The button above has been clicked {{ counter }} times.</p>
    <button v-on:click="say('Hi')">Hi</button>
</div>
<script>
var vm = new Vue({
    el: '#app',
    methods: {
        say: function(msg) {
            alert(msg);
        }
    },
    data: {
        counter: 0,
    }
});
</script>
```

###自定义指令
Vue除了核心指令外也允许注册自定义指令,语法Vue.directive('directiveName', {[钩子函数][3]{:target="_blank"}})

```html
<div id="app">
    <p>页面载入时,input 元素自动获取焦点:</p>
    <input v-focus>
</div> 
<script>
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    el.focus();
  }
})
new Vue({
  el: '#app'
})
</script>
```

##2.3组件
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
![components](http://localhost:8080/img/vue/components.png)
那么什么是组件呢?
组件是Vue.js最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能。在有些情况下,组件也可以是原生HTML元素的形式,以is特性扩展。
###基本步骤
Vue.js的组件的使用有3个步骤:创建组件构造器、注册组件和使用组件。
```html
<div id="app">
    <!-- 3. #app是Vue实例挂载的元素,应该在挂载元素范围内使用组件-->
    <my-component></my-component>
</div>
<script>
// 1.创建一个组件构造器
var myComponent = Vue.extend({
    template: '<div>This is my first component!</div>'
});

// 2.注册组件,并指定组件的标签,组件的HTML标签为<my-component>
Vue.component('my-component', myComponent);

// 3. 实例化组件
new Vue({
    el: '#app'
});
</script>
```
**批注**

1. Vue.extend() 是Vue构造器的扩展,调用Vue.extend()创建的是一个组件构造器,该构造器有一个选项对象,选项对象的template属性用于定义组件要渲染的html。
2. Vue.component() 是注册组件,创建一个组件实例;需要2个参数,第一个参数是自定义组件的标签,第二个参数是组件的构造器。
3. 组件需要挂载到某个Vue的实例下,否则不生效。

###全局注册和局部注册
调用```Vue.component()```注册组件时,组件的注册是全局的,这意味着该组件可以在任意Vue示例下使用。
如果不需要全局注册,或者是让组件使用在其它组件内,可以用选项对象的components属性实现局部注册。

```html
<div id="app">
    <!--  my-component只能在#app下使用-->
    <my-component></my-component>
</div>
<div id="app2">
    <!-- 不能使用my-component组件,因为my-component是一个局部组件,它属于#app-->
    <my-component></my-component>
</div>
<script>
new Vue({ el: '#app', components: { 'my-component': myComponent } });
</script>
```

###父组件和子组件
在一个组件中包含另一个组件,那么另一个组件就是该组件的子组件。
```html
<div id="app">
    <parent-component>
    </parent-component>
</div>
<script>
var Child = Vue.extend({
    template: '<p>This is a child component!</p>'
})
var Parent = Vue.extend({
    // 在Parent组件内使用<child-component>标签
    template: '<p>This is a Parent component</p><child-component></child-component>',
    components: {
        // 局部注册Child组件,该组件只能在Parent组件内使用
        'child-component': Child
    }
})
// 全局注册Parent组件
Vue.component('parent-component', Parent);
new Vue({
    el: '#app'
})
</script>
```
**流程**
![父子组件](http://localhost:8080/img/vue/parent-chlid.png)
Child组件是在Parent组件中注册的,它只能在Parent组件中使用,确切地说:**子组件只能在父组件的template**中使用。
####父子组件通信
组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
![父子通信](http://localhost:8080/img/vue/props-events.png)
**Prop**
> prop默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意修改了父组件的状态

```html
<div id="container1">
    <component1 v-bind:my-name="name" v-bind:my-age="age"></component1>
</div>
<template id="myComponent">
    <table>
        <tr>
            <th colspan="2">
                子组件数据
            </th>
        </tr>
        <tr>
            <td>myName</td>
            <td>{{ myName }}</td>
        </tr>
        <tr>
            <td>myAge</td>
            <td>{{ myAge }}</td>
        </tr>
    </table>
</template>
<script type="text/javascript">
new Vue({
    el: '#container1',
    data: {
        name: 'longen',
        age: 30
    },
    components: {
        'component1': {
            template: '#myComponent',
            props: ['myName', 'myAge']
        }
    }
})
</script>
```

 为了便于理解,你可以将这个Vue实例看作my-component的父组件。
**on与emit**
父组件使用props传递数据给子组件,但是如果子组件需要把数据传回去的话,就需要自定义事件了
>使用 $on(eventName) 监听事件
>使用 $emit(eventName) 触发事件

```html
   <div id="app">
        <chlid v-bind:message="parentMsg" v-on:listen="showMsgFromChlid"></chlid>
    </div>
    <template id="myComponent">
        <div>
            <h2>Chlid 子组件</h2>
            <P>{{message}}</P>
            <button v-on:click="sendMsgToParent">向父组件传值</button>
        </div>
    </template>
</body>
<script>
Vue.component('chlid', {
    props: ["message"],
    template: '#myComponent',
    methods: {
        sendMsgToParent: function(data) {        
            this.$emit("listen", "this is a msg from chlid");
        }
    }
});
new Vue({
    el: '#app',
    data() {
        return { parentMsg: "hello,child" }
    },
    methods: {
        showMsgFromChlid: function(data) {
            console.log(data);
        }
    }
});
</script>
```


###语法糖
1. 使用Vue.component()直接创建和注册组件。``` Vue.component('component1', { template: '<div>hello</div>' });```
Vue.component()的第一个参数是标签名称,第二个参数是一个选项对象,使用选项对象的template属性定义,使用该方式,在Vue源码中会调用Vue.extend()方法。
2. script标签或template标签

> 但在template选项中拼接HTML元素比较麻烦,这也导致了HTML和JavaScript的高耦合性。Vue.js提供了两种方式将定义在JavaScript中的HTML模板分离出来。

```html
<div id="app">
    <my-component1></my-component1>
    <my-component2></my-component2>
</div>
<script type='text/x-template' id="myComponent1">
    <div>hello</div>
</script>
<template id="myComponent2">
    <div>world</div>
</template>
<script>
new Vue({
    el: '#app',
    components: {
        'my-component1': {
            template: '#myComponent1'
        },
        'my-component2': {
            template: '#myComponent2'
        }
    }
})
</script>
```
结果
![scriptAndTemp](http://localhost:8080/img/vue/scriptAndTempTest.png)

#3.Vue构建
* node.js环境(npm包管理器)
* vue-cli 脚手架构建工具
* webpack 模块打包机

```shell
# 全局安装 vue-cli
npm install -g vue-cli
# 创建一个基于 webpack 模板的新项目
vue init webpack my-project
cd my-project
# 安装依赖
npm install
npm run dev
```
输入lobalhost:8080出现以下页面就代表成功
![index](http://localhost:8080/img/vue/index.png)
package.json的```scripts```指定了运行脚本命令的npm命令行缩写,比如start指定了运行npm run dev。
```json
"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "unit": "jest --config test/unit/jest.conf.js --coverage",
    "e2e": "node test/e2e/runner.js",
    "test": "npm run unit && npm run e2e",
    "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
    "build": "node build/build.js"
}
```

工程目录如图所示
![catalogue](http://localhost:8080/img/vue/catalogue.png)

[1]: https://www.zhihu.com/question/51907207
[2]: https://zhuanlan.zhihu.com/p/23134551
[3]: https://cn.vuejs.org/v2/guide/custom-directive.html#钩子函数
[4]: http://cnodejs.org/topic/5994ffa0ee602e88524b4325
[^1]:当大量数据变动时,所有受到影响的watcher会被推送到一个队列中,并且每个watcher只会推进队列一次。这个队列会在进程的下一个tick异步执行。这个机制可以避免同一个数据多次变动产生的多余DOM操作,也可以保证所有的DOM写操作在一起执行,避免DOM读写切换可能导致的layout。

This snippet took 0.01 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).