VueJs 学习笔记

VueJs学习笔记

参考资料:https://cn.vuejs.org/javascript

特效库:TweenJS(补间动画库)  VelocityJS(轻量级JS动画库)  Animate.css(CSS预设动画库)css

比较其余框架:https://cn.vuejs.org/v2/guide/comparison.htmlhtml

Github:vue2-elm  前端

安装

npm install vuevue

使用时推荐安装:Vue Devtools 能够方便调试 https://github.com/vuejs/vue-devtools#vue-devtoolsjava

安装命令行,快速搭建大型单页应用node

npm install --g vue-cli webpack

vue init webpack my-projectgit

npm run devgithub

声明式渲染

Vue容许你采用简洁的模板语法来声明式将数据渲染进Dom。

此时app.message会进行双向绑定,修改的同时也会改变Dom渲染。称为响应式元素

<div id="app">
    {{message}}
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message:"Hello Vue"
        }
    });
</script>

除了声明式渲染,还可使用v-bind指令来绑定数据。v-bind属性称为指令,指令带有前缀v-。以表示它是Vue.js提供的特殊属性

会在渲染过的DOM上应用特殊的响应式行为。这个指令意思是把title属性和Vue的message绑定在一块儿。

<div id="app">
    <span v-bind:title="message">
        Hello 
    </span>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message:"Hello Vue"
        }
    });
</script>

判断与循环

控制切换一个元素,使用v-if。不只能够绑定文本到数据,也能够绑定Dom结构

<div id="app">
    <span v-if="seen">
        Hello 
    </span>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            seen:false
        }
    });
</script>

v-for 能够绑定数据到数组循环一个列表

<div id="app">
    <ol>
        <li v-for="todo in items"></li>
    </ol>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            items:[
                {
                    text:"A"
                },{
                    text:"B"
                },{
                    text:"C"
                }
            ]
        }
    });
</script>

处理用户输入

使用v-on指令能够绑定一个监听事件用于调用咱们Vue实例中的方法

<div id="app">
    <p>{{message}}</p>
    <button v-on:click="reverSetMessage">Click</button>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message:"Hello"
        },
        methods:{
            reverSetMessage:function(){
                this.message = "123";
            }
        }
    });
</script>

使用v-model可使表单输入和应用状态中作双向绑定。当其中一个修改时,会同时修改另外一个

<div id="app">
    <p>{{message}}</p>
    <input type="text" v-model="message" />
</div>
<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message:"Hello"
        }
    });
</script>

组件构建应用

组件系统是Vue.js另外一个重要的概念,由于它提供了一种抽象,让咱们能够用独立可复用的小组件来构建大型应用。

在Vue里一个组件实质上是一个拥有预约义选项的一个Vue实例。使用component能够建立组件,能够在另外一个地方写入它。

咱们定义一个接受字段,props["todo"],使系统能够接受todo参数。使用v-bind指令将前面v-for循环的变量,传给todo

而后在组件的template就能够进行渲染了。

<div id="app">
        <ol>
            <todo-item v-for="item in groceryList" v-bind:todo="item"></todo-item>
        </ol>
    </div>
    <script type="text/javascript">
        Vue.component('todo-item', {
            props:["todo"],
            template: '<li>{{todo.text}}</li>'
        })
        var app = new Vue({
            el:"#app",
            data:{
                groceryList:[
                    {"text":"Vegetables"},
                    {"text":"Cheese"},
                    {"text":"Whatever else humans"}
                ]
            }
        })
    </script>

在这个例子中,咱们将应用分割成两个更小的单元,子元素经过props接口实现了与父元素很好的解耦

咱们能够在不影响到父应用的基础上将应用总体分割成一个个小组件。最终可能页面只是如下面这种形式展示

<div id="app">
  <app-nav></app-nav>
  <app-view>
    <app-sidebar></app-sidebar>
    <app-content></app-content>
  </app-view>
</div>

构造器 

每一个Vue应用都是经过构造函数Vue建立的Vue根实例启动的。vm变量代表Vue实例

var vm = new Vue({
            //选项
        })

在实例化Web时,须要传入选择对象,能够包含数据、模板、挂载元素、方法、生命周期钩子等选择。Api地址

能够扩展Vue构造器,从而用预约义选项建立可复用的组件构造器,Vue的组件其实都是被扩展的Vue实例

var MyComponent = Vue.extend({
  // 扩展选项
})
// 全部的 `MyComponent` 实例都将以预约义的扩展选项被建立
var myComponentInstance = new MyComponent()

属性和方法

每一个Vue实例都会代理其data对象里全部的属性。这些被代理的属性也是响应式的

var data = { a: 1 }
var vm = new Vue({
  data: data
})
vm.a === data.a // -> true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // -> 2
// ... 反之亦然
data.a = 3
vm.a // -> 3

 除了data属性,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 (newVal, oldVal) {
  // 这个回调将在 `vm.a`  改变后调用
})

生命周期 

每一个Vue实例被建立以前都要通过一系列的初始化过程。在这个过程当中会调用一些生命周期钩子,给咱们提供执行自定义逻辑的机会。

例如,created钩子。钩子的this指向vm实例

<div id="app">
        {{message}}
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:"Hello"
            },
            created:function(){
                console.log("created钩子");
            }
        })
    </script>

执行顺序以下:

new Vue()、beforeCreate钩子、检查数据、初始化事件、

created钩子、模板渲染、beforeMount钩子、建立vm.$el、mounted钩子

Mounted、beforeDestrory钩子、事件监听器、销毁、destroyed钩子

模板语法

Vue使用基于HTML模板语法、容许声明式的将DOM绑定至底层Vue实例数据。

全部Vue的模板都是合法的HTML,都能被浏览器和HTML解析器进行解析。

插值

文本

数据绑定最多见的就是Mustache语法(双大括号)文本插值。能够进行响应式绑定

<span>Message:{{msg}}</span>

使用v-once指令,能够一次性的插值,当数据改变时不会更新

<span v-once>Message:{{msg}}</span>

纯HTML

使用v-html,被插入的内容都会当作HTML处理。但容易致使XSS攻击

<div v-html="rawHtml"></div>

属性

Mustache语法不能再属性里使用。在属性中须要使用v-bind

<div v-bind:id="dynamicId"></div>

<button v-bind:disabled="boolBtn">Button</div> //能够控制按钮可否使用

使用Js表达式

Vue提供了JavaScript表达式支持。能够在Mustache语法中直接写Js

{{ alert(123); }}

指令

v-if 指令根据表达式的值来移除/插入Dom元素

<p v-if="seen">Now you See</p>

参数

一些指令能接受一个参数,在指令后以冒号指明。

<a v-bind:href="url"></a>

<a v-on:click="aClick"></a>

修饰符

指明特殊后缀,用于指出一个指定应该以特殊方法绑定。例如:.prevent修饰符告诉v-on指令对于触发的事件采用event.preventDefault()

例如,禁止冒泡。<form v-on:submit.prevent="onSubmit"></form>

过滤器

Vue容许您定义过滤器,被用做一些常见的文本格式化,过滤器应该被加载mustache尾部,有管道符指示

过滤器只能在mustanche和v-bind中使用。使用filters定义

{{message|capitalize}}

<div v-bind:id="rawId | formatId"></div>

过滤器函数总接受表达式的值做为第一个参数。能够在过滤器中对值进行修改返回便可。例以下方输出的是321而不是Hello

<div id="app">
        {{message | capital}}
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:"Hello"
            },
            filters:{
                capital:function(value)
                {
                    console.log(value);
                    return "321";
                }
            }
        })
    </script>

缩写

v-bind可缩写成:。例如:<a v-bind:href="url"></a> == <a :href="url"></a>

v-on可缩写成@。例如:<a v-on:click="aClick"></a> == <a @click="aClick"></a>

计算属性

模板中绑定表达式只用于简单的操做。若是须要进行逻辑操做,应当使用计算属性 computed

计算属性只是做为message的getter。若是改变revermessage是无效的

<div id="app">
        <p>{{message}}</p>
        <p>{{reverMessage}}</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:"Hello"
            },
            computed:{
                reverMessage:function(){
                    return this.message.split('').reverse().join('');
                }
            }
        })
    </script>

计算属性默认只有getter,不过咱们也能够显示添加一个setter

computed: {
  reverMessage: {
    // 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]
    }
  }
}

方法

咱们能够定义Method方法,在mustanche中进行调用。

方法和计算属性不一样的是,计算属性依赖于缓存,只有相关依赖发生改变时才会重新取值。

也就是说只要message没有改变,reverMessage就不会进行计算,也不会执行函数。

<div id="app">
        <p>{{message}}</p>
        <p>{{reverMessage()}}</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:"Hello"
            },
            methods:{
                reverMessage:function(){
                    return this.message.split('').reverse().join('');
                }
            }
        })
    </script>

观察Watchers(异步进行Ajax操做)

当你想要在数据变化时,执行异步操做或开销较大的操做,这是颇有用的。例如Ajax

<div id="watch-example">
        <p>
            输入文本会进行监控查询:
            <input v-model="question">
        </p>
        <p>
            {{message}}
        </p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                question: '',
                message: "Hello"
            },
            watch: {
                question: function (newQuery) {
                    this.message = "正在查询...";
                    this.getAnswer()
                }
            },
            methods: {
                getAnswer: function(){
                    //执行Ajax操做
                    this.message = this.question;
                }
            }
        })
    </script>

绑定Html Class

对象语法

能够传给 v-bind:class一个对象,以动态切换class。下面语法表示若是isActive为真,则就给div的class赋值active。

<div class="divRed" v-bind:class="{active:isActive}"></div>

绑定class与原有class不冲突。能够传多个值来切换多个class

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

当isActive或hasError发生变化时,class列表将相应的更新。例如:hasError = true。渲染为:div class="static active text-danger"

能够直接绑定一个对象。而后在data中对这个对象的class,进行布尔赋值

<div v-bind:class="classObject" id="watch-example">
        <p>
            {{message}}
        </p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                message: "Hello",
                classObject: {
                    active: true,
                    active2: false
                }
            }
        })
    </script>

这个时候,若是咱们须要对class进行逻辑计算而后在赋值。就可使用计算属性。这是一个经常使用且强大的模式

<div v-bind:class="classObject" id="watch-example">
        <p>
            {{message}}
        </p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                message: "Hello"
            },
            computed: {
                classObject: function () {
                    if (this.message == "Hello") {
                        return {
                            active: true,
                            active2: false
                        }
                    } else {
                        return {
                            active: true,
                            active2: true
                        }
                    }
                }            
             }
        })
    </script>

数组语法

能够把一个数组传给v-bind:class,以应用一个列表

<div v-bind:class="[isActive,isActive2]" id="watch-example">
        <p>
            {{message}}
        </p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                message: "Hello",
                isActive:"active",
                isActive2:"active2"
            },
        })
    </script>

也能够根据条件来进行切换。使用三元运算符

<div v-bind:class="[true ? isActive : '',isActive2]" id="watch-example">

也能够将对象绑定和数组绑定混用

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

绑定Style

对象语法

v-bind:style 语法十分直观

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

data: {
                activeColor:"red",
                fontSize:"10"
            }

一般直接绑定到一个样式对象更加清晰。

<div v-bind:style="styleObject" id="watch-example">
        <p>
            {{message}}
        </p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                message: "Hello",
                styleObject:{
                    color:"red",
                    fontSize:"10px"
                }
            }
        })
    </script>

数组语句

v-bind:style 数据数组能够将多个样式对象应用到一个元素上

<div v-bind:style="[active,active2]">

自动添加前缀

当v-bind:style使用须要特定前缀的CSS属性时,如transform。Vue会自动监听并添加对应前缀

条件渲染

咱们可使用v-if和v-else,实现逻辑判断功能。

<div v-bind:style="styleObject" id="watch-example">
        <p v-if="ok">Yes</p>
        <p v-else>No</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                ok:true
            }
        })
    </script>

v-else 必须紧跟着v-if,否则不会进行渲染。

template包装渲染

可使用template标签来包装一组标签,进行渲染

<div id="watch-example">
        <template v-if="ok">
            <p>1</p>
            <p>2</p>
            <p>Yes</p>
        </template>
        <p v-else>No</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                ok: true
            }
        })
    </script>

在Vue2.1中,新增了v-else-if。能够链式的屡次使用

Key控制元素重用

使用key能够控制元素重用。例以下面代码,当容许用户在不一样的登陆方式之间切换。若是不添加key,则输入的数据会保存

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

v-show

与v-if相似,只不过v-show会先进行渲染,操做CSS属性display

v-show 与 v-if相比

v-if是真实的条件渲染,会确保条件快在切换中适当地销毁与重建。也是惰性的,若是在初始化渲染时条件为假,则什么也不作

通常来讲v-if有更高的切换消耗,v-show有更高的初始化消耗。频繁切换用v-show,运行条件不大可能改变用v-if

v-for

v-for用来根据一组数据的选择列表来渲染。v-for指令须要item in items形式的特殊语法

基本使用

<ul id="watch-example">
            <li v-for="item in items">
                {{item.message}}
            </li>
        </ul>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                items:[
                    {"message":"Foo"},
                    {"message":"Bar"}
                ]
            }
        })
    </script>

 

v-for还支持第二个可选参数当作当前索引

<li v-for="(item,index) in items">
                {{item.message}} + {{index}}
            </li>

template

跟v-if同样,v-for也可使用template

对象迭代

也可使用v-for 进行一个对象迭代处理。会输出每一个对象的值

<ul id="watch-example">
        <li v-for="(value,index) in object">
            {{value}} + {{index}}
        </li>
    </ul>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                object: {
                    FirstName: "A",
                    LastName: "B",
                    Old: 12
                }
            }
        })
    </script>

也能够提供第二个的参数为键名

<div v-for="(value, key) in object">
  {{ key }} : {{ value }}
</div>

第三个参数为索引

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }} : {{ value }}
</div>

整数迭代

v-for能够取整数,在这种状况下会重复屡次

<div>
  <span v-for="n in 10">{{ n }}</span>
</div>

Key

当Vue用v-for正在更新已渲染过的元素列表时,默认若是数据项的顺序被改变,Vue将不是移动Dom元素来匹配数据项的顺序。

而是简单复用此处每一个元素,确保已经渲染过了。为了让Vue从新排序现有元素,须要给每一项提供一个key

<div v-for="item in items" v-bind:key="item.id">
  <!-- 内容 -->
</div>

事件处理器

监听事件

能够用v-on来监听DOM事件触发一些代码

 <div id="watch-example">
        <button v-on:click="counter+=1">add</button>
        <p>{{counter}}</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                counter:0
            }
        })
    </script>

方法事件处理器

v-on能够定义一个方法来执行复杂的逻辑操做

<div id="watch-example">
        <button v-on:click="greet">add</button>
        <p>{{counter}}</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                counter:0
            },
            methods:{
                greet:function(){
                    this.counter += 1;
                }
            }
        })
    </script>

也能够直接显示调用方法。vm.greet();

方法传参

除了上面这种方法调用,还能够给方法传递参数。

<div id="watch-example">
        <button v-on:click="greet(1)">add</button>
        <p>{{counter}}</p>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data: {
                counter: 0
            },
            methods: {
                greet: function (count) {
                    this.counter = count += 1;
                }
            }
        })
    </script>

$event

若是须要在方法里访问原生DOM事件,能够用特殊变量$event把它传入方法

<button v-on:click="warn('Form cannot be submitted yet.', $event)">Submit</button>

// ...
methods: {
  warn: function (message, event) {
    // 如今咱们能够访问原生事件对象
    if (event) event.preventDefault()
    alert(message)
  }
}

事件修饰符

在事件处理程序中调用 event.preventDefault()阻止事件默认行动、event.stopPropagation()中止事件传播(禁止冒泡)

是很是常见的需求,虽然咱们能够在methods中轻松实现这点,但更好的方式是methods只有纯粹的数据逻辑,而不处理Dom事件细节

为了解决此问题,Vue.js为 v-on 提供了事件修饰符,经过由 . 表示的指令后缀来调用修饰符

<!-- 阻止单击事件冒泡 -->
<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>
<!-- 只当事件在该元素自己(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>

//2.14新增
<!-- 将触发单击事件最多一次 -->
<a v-on:click.once="doThis"></a>

按键修饰符

在监听键盘事件时,咱们常常须要监测常见的键值。Vue容许为v-on在监听键盘事件时添加按键修饰符

<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">
<input v-on:keyup.enter="submit">

Vue为最经常使用的按键定义了别名

所有的按键别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

2.10新增

  • .ctrl
  • .alt
  • .shift
  • .meta

表单控件绑定

基础用法

能够用 v-model 指令在表单控件元素上建立双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。

文本

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

多行文本

<span>Multiline message is:</span>
<p style="white-space: pre">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>

复选框

v-model 绑定的值 为 true 或 false

<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label> 
<input
  type="checkbox"
  v-model="toggle"
  v-bind:true-value="a"
  v-bind:false-value="b"
>

// 当选中时
vm.toggle === vm.a
// 当没有选中时
vm.toggle === vm.b

多选框

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>

new Vue({
  el: '...',
  data: {
    checkedNames: []
  }
})

单选框

v-model 绑定的值为 value。One 或者 Two

<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
<input type="radio" v-model="pick" v-bind:value="a">

// 当选中时
vm.pick === vm.a

多选列表

v-model绑定的值,在选中的状况下为 option的value

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>

动态选项

<select v-model="selected">
  <option v-for="option in options" v-bind:value="option.value">
    {{ option.text }}
  </option>
</select>
<span>Selected: {{ selected }}</span>

new Vue({
  el: '...',
  data: {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' },
      { text: 'Three', value: 'C' }
    ]
  }
})
<select v-model="selected">
    <!-- 内联对象字面量 -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>

// 当选中时
typeof vm.selected // -> 'object'
vm.selected.number // -> 123

修饰符

.lazy

默认状况下,v-model在input事件中同步输入框的值和数据。但能够添加一个修饰符lazy,从而转变为change事件中同步

<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

若是想自动将用户输入的值转换为number,若是转换不成功则返回原值。能够添加一个.number修饰符给v-model来处理

<input v-model.number="age" type="number">

.trim

能够过滤用户输入的首尾空格

<input v-model.trim="msg">

组件

组件是VueJs最强大的功能之一,组件能够扩展HTML元素,封装可重用代码。在较高层面上,组件是自定义元素,VueJs为他添加特殊功能。

有些状况下,组件也能够是原生HTML元素的形式,以is特性扩展。

注册

要注册一个全局组件,可使用Vue.component(tagName,options)。标签名使用W3C规则,小写而且包含一个短杠

Vue.component("Demo-component",{
            //操做
        });

组件注册以后,则能够在页面中使用了。

<div id="watch-example">
        <demo-component></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component",{
            template:"<div>A Custome</div>"
        });

        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

有时候咱们不须要全局注册,可使用局部注册(components),只针对本页面和父页面进行显示。

<div id="watch-example">
        <demo-component></demo-component>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            components: {
                "demo-component": {
                    template: "<div>A Custome</div>"
                }
            }
        })
    </script>

DOM模板解析说明 

当使用Dom做为模板时,会受到一些HTML限制,由于Vue只有在浏览器解析和标准化HTML后才能获取内容。

例如:<ul>、<ol>、<table>、<select>限制了能包裹的属性。致使在这些标签下进行组件会被认为是无效内容。

可是也有变通的方法,可使用特殊的 is 属性。

data必须是函数

使用组件的时候,大多数能够传到Vue构造器中的选项均可以在注册组件时使用。可是有一个例外,data 必须是函数。

若是咱们在组件中写以下代码。会受到报错:The "data" option should be a function that returns a per-instance value in component definitions

 <div id="watch-example">
        <demo-component></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component",{
            template:"<div>{{message}}</div>",
            data:{
                message:"Hello"
            }
        })
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

提示data必须是一个函数,因此咱们修改成以下代码

<div id="watch-example">
        <demo-component></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component", {
            template: "<div>{{message}}</div>",
            data: function () {
                return {
                    message: "Hello"
                }
            }
        })
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

构成组件

组件意味着协同工做,一般父子组件会是这样的关系。组件在A在它的模板中使用了组件B,他们之间是必然须要通讯的。

父组件给子组件传递数据,子组件须要将它内部发生的事情告知父组件。

然而,在一个良好的接口定义中尽量的将父子组件解耦是很重要的。这保证了每一个组件能够在相对隔离的环境中书写和理解

也大幅提升了组件的可维护性和可重用性。

在Vue中,父子组件的关系能够总结为:props down 属性向下、event up 事件向上。父组件经过props向下传递数据给子组件

子组件经过event给父组件发送消息。

Prop

使用Prop传递数据

组件的实例做用域是孤立的,子组件不能直接引用父组件的数据。但可使用props吧数据传给子组件

message 是父组件用来传递数据的一个自定义属性,子组件须要显示地使用props选项声明“message”

<div id="watch-example">
        <demo-component message="Hello World"></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component", {
            props:["message"],
            template:"<span>{{message}}</span>"
        });
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

传递过来的值,跟data是同样的,均可以直接绑定。例如:绑定style

 <div id="watch-example">
        <demo-component message="Hello World" size="10px"></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component", {
            props: ["message", "size"],
            template: "<span style='font-size:10px' v-bind:style={fontSize:size}>{{message}}</span>"
        });
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

动态属性

使用v-bind能够动态绑定属性到父组件中。每当数据变化,该变化也会传到子组件

<div id="watch-example">
        <input v-model="parentMsg" />
        <demo-component :message="parentMsg" size="10px"></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component", {
            props: ["message", "size"],
            template: "<span style='font-size:10px' v-bind:style={fontSize:size}>{{message}}</span>"
        });
        var vm = new Vue({
            el: "#watch-example",
            data:{
                parentMsg:''
            }
        })
    </script>

传递数值

若是想要给组件传递一个数字,是不可使用常量传递的。由于它传递的并非实际的数字。例如

<div id="watch-example">
        <demo-component size="10"></demo-component>
    </div>
    <script type="text/javascript">
        Vue.component("demo-component", {
            props: ["message", "size"],
            template: "<div><button v-on:click=add>add</button><span>{{size}}</span></div>",
            methods:{
                add:function(){
                    this.size += 1;
                }
            }
        });
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

demo-component size是常量传递,也就是传递的字符串。那么在add方法中,实际上会变成 1011111 这种形式

因此咱们针对数字传递时,要使用 v-bind:size 或者 :size

咱们尽可能不要直接操做传递过来的值,因此咱们使用data或者计算属性,来完成操做 

Vue.component("demo-component", {
            props: ["message", "size"],
            template: "<div><button v-on:click=add>add</button><span>{{cSize}}</span></div>",
            data: function () {
                return {
                    cSize: this.size
                }
            },
            methods: {
                add: function () {
                    this.cSize += 1;
                }
            }
        });

单向数据流

prop是单向绑定的,也就是说父组件的属性变化时,将传导给子组件。但不会反过来。这是为了怕子组件,改变父组件的状态

每次父组件更新时,子组件的全部prop也会更新。这意味着,咱们不能在子组件改变prop的状态。Vue会提出警告。

一般有两种改变prop的状况,

1.prop做为初始值传入,子组件以后只是将它的初始值做为本地数据的初始值使用

2.prop做为须要被转变的原始值传入

那么,咱们可使用两种方式来应对转变

1.使用data属性,并将prop的初始值做为局部数据的初始值

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

2.使用计算属性,此属性从prop的值计算得出

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

注意:JavaScript中对象和数组是引用类型,在组件中改变,父组件也会随之改变

Prop验证

组件能够为props指定验证要求,若是未指定验证要求,Vue会发出警告。

Vue.component('example', {
  props: {
    // 基础类型检测 (`null` 意思是任何类型均可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

type 能够是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

type 也能够是一个自定义构造器,使用 instanceof 检测。

自定义事件

父组件是使用props传递数据给子组件,若是子组件要把数据传回给父组件。就须要使用自定义事件

v-on绑定自定义事件

每一个Vue实例都实现了事件接口

使用 $on(eventName) 监听事件

使用 $emit(eventName) 触发事件

父组件能够在使用子组件的地方直接用v-on来监听子组件触发的事件

 <div id="watch-example">
        <p>{{total}}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
    <script type="text/javascript">
        Vue.component("button-counter", {
            template: "<button v-on:click=increment>{{counter}}</button>",
            data: function () {
                return {
                    counter:0
                }
            },
            methods: {
                increment: function () {
                    this.counter+=1;
                    this.$emit("increment")
                }
            }
        });
        var vm = new Vue({
            el: "#watch-example",
            data:{
                total:0
            },
            methods:{
                incrementTotal:function(){
                    this.total += 1;
                }
            }
        })
    </script>

使用自定义事件的表单输入组件

自定义事件也能够用来建立自定义的表单输入组件,使用v-model 来进行数据双向绑定

<input v-model="something">

只是一个语法糖,它对应的语句是

<input v-bind:value="something" v-on:input="something = $event.target.value">

<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>

$event.target.value 意思是最初触发事件的DOM元素

要让v-model生效,必须接受一个value属性、在有新的value时触发input事件。

ref = "sel",这是Vue2.0的特性,添加此特性才能够$ this.$refs.sel.value

一个简单的下拉框例子。每次下拉都会往前推进一个位置

<div id="watch-example">
        <currency-input v-model="price"></currency-input>
    </div>
    <script type="text/javascript">
        Vue.component("currency-input", {
            template: '\
               <span>\
                 <select ref="sel" v-bind:value="value" v-on:change="updateValue($event.target.value)">\
                    <option value ="1">Volvo</option>\
                    <option value ="2">Saab</option>\
                    <option value="3">Opel</option>\
                    <option value="4">Audi</option>\
                </select>\
                </span>\
                ',
            props: ["value"],
            methods: {
                updateValue: function (value) {
                    var formattedValue = Number(value);
                    if (formattedValue < 4) {
                        formattedValue += 1;
                    } else {
                        formattedValue = 1;
                    }
                    if (formattedValue !== value) {
                        this.$refs.sel.value = formattedValue
                    }
                    this.$emit('input', formattedValue);
                }
            }
        });
        var vm = new Vue({
            el: "#watch-example",
            data: {
                price: "1"
            }
        })
    </script>

 

使用Slot分发内容

在使用组件时,常常须要像这样组合它们

<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>

有两点须要注意:

1. <app> 组件不知道它的挂载点会有什么内容。挂载点的内容是由<app>的父组件决定的

2. <app> 组件极可能有它本身的模板

为了让组件能够组合,咱们须要一种方式来混合父组件的内容与子组件本身的模板。

这个过程称为 内容分发 。Vue实现了一个内容分发API。使用特殊的slot元素做为原始内容的插槽

编译做用域 

<child-component>
  {{ message }}
</child-component>

上面例子中,message应该绑定到父组件的数据。

组件做用域简单地说

父组件模板的内容在父组件做用域内编译;

子组件的模板内容在子组件做用域内编译;

例以下面的代码,就不会再子组件中运行

<child-component v-show="someChildProperty"></child-component>

单个Slot

对于下面这种状况,除非子组件模板包含一个<slot>插口,不然父组件的内容将会丢弃

<child-component>
  {{ message }}
</child-component>

当子组件只有一个<slot>而且没有属性的时候,父组件整个内容片断将插入到slot所在的DOM位置,而且替换到slot标签自己

最初写在slot标签底下的内容都被视为备用内容。只有宿主元素为空,且没有要插入的内容时才会显示

假定子组件有下面的模板

<div>
  <h2>我是子组件的标题</h2>
  <slot>
    只有在没有要分发的内容时才会显示。
  </slot>
</div>

父组件

<div>
  <h1>我是父组件的标题</h1>
  <my-component>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </my-component>
</div>

渲染结果

<div>
  <h1>我是父组件的标题</h1>
  <div>
    <h2>我是子组件的标题</h2>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </div>
</div>

具名Slot

slot元素能够用一个特殊的属性name来配置如何分发内容。多个slot能够有多个不一样的名字。

具名slot将匹配内容片断中有对应slot特性的元素。

仍然能够由一个匿名的slot。它是默认的slot。做为找不到内容片断的备用插槽。若是没有默认的slot,找不到的内容会被抛弃

例以下面的例子。使用自定义属性slot后面跟名字来指定

<div id="watch-example">
        <currency-input>
            <h1 slot="header">页面标题</h1>
            <p>主要内容</p>
            <p>另外一个主要内容</p>
            <p slot="footer">联系信息</p>
        </currency-input>
    </div>
    <script type="text/javascript">
        Vue.component("currency-input", {
            template: '\
                        <div class="container">\
                            <header>\
                                <slot name="header"></slot>\
                            </header>\
                            <main>\
                                <slot></slot>\
                            </main>\
                            <footer>\
                                <slot name="footer"></slot>\
                            </footer>\
                        </div>\
                        '
        });
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

上面代码渲染的状况为

<div class="container">
  <header>
    <h1>这里多是一个页面标题</h1>
  </header>
  <main>
    <p>主要内容的一个段落。</p>
    <p>另外一个主要段落。</p>
  </main>
  <footer>
    <p>这里有一些联系信息</p>
  </footer>
</div>

做用域插槽

做用域插槽是一种特殊类型。2.1.0新增,使用一个可重用模板替换已渲染的元素。

子组件中,只需将数据传递到插槽,就像prop传递给组件同样。

在父级组件中,具备特殊属性scope的<template>元素,表示它是做用域插槽的模板。scope的值对应一个临时变量

此变量接受从子组件中传递的prop对象。

动态组件

多个组件可使用一个挂载点,使用 内链组件 components 可让他们动态切换

<div id="watch-example">
        <component v-bind:is="currentView"></component>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#watch-example",
            data:{
                currentView:"A"
            },
            components:{
                A:{
                    template:"<div>childA</div>" 
                },
                B:{
                    template: '<div>childB</div>'
                }
            }
        })
    </script>

咱们修改vm.currentView就能够实现组件切换的功能了

也能够直接绑定到组件对象上,不过不推荐这种使用

var Home = {
  template: '<p>Welcome home!</p>'
}
var vm = new Vue({
  el: '#example',
  data: {
    currentView: Home
  }
})

keep-alive

若是须要把切换的组件保留在内存中,而不是重新渲染。能够添加keep-alive标签,嵌套调用组件

<keep-alive>
            <component v-bind:is="currentView"></component>
        </keep-alive>

这样能够保留状态,不进行重新渲染。

编写可复用的组件

在编写组件时要考虑是否须要复用组件,可复用组件应当定义一个清晰的公开接口

Vue组件的API来自三部分:props,events,slots

Props:容许外部环境传递数据给组件

Events:容许组件触发外部环境的反作用

Slots:容许外部环境将额外的内容组合在组件中

在调用过程当中,使用v-bind 和 v-on的简写语法。会让模板变得更加简洁

<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat"
>
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>
</my-component>

子组件索引

尽管有props和events,可是有时候仍然须要在js中直接访问子组件。为此可使用ref为子组件指定一个索引ID

<div id="parent">
  <user-profile ref="profile"></user-profile>
</div>

var parent = new Vue({ el: '#parent' })
// 访问子组件
var child = parent.$refs.profile

当ref和v-for一块儿使用时,ref是一个数组或对象,包含相应的子组件

$refs 只在组件渲染完成之后才填充,而且它是非响应式的。仅仅做为访问子组件的应急方案。尽可能避免使用

异步组件 

在大型应用中,咱们可能须要将应用拆分红多个小模块,按需下载。为了让事情更简单,Vue容许将组件定义为一个工厂函数。

动态解析组件的定义。Vue只在组件须要渲染时触发工厂函数,而且把结果缓存起来,用于后面再次渲染。

例以下面代码,咱们能够把组件模板提取出来

 Vue.component("hello-world", function(resolve,reject){
            $.get("./xtemplate.html").then(function(res){
                resolve({
                    template:res
                })
            });
        });

可是咱们在使用Vue的时候,尽可能摆脱掉jQuery,咱们可使用 vue-resource https://github.com/pagekit/vue-resource

咱们引用完vue-resource之后,就能够替代jQuery的ajax了

使用vue-resource的代码以下:

Vue.component("cxy-demo4", function (resolve, reject) {
    Vue.http.get("/xtemplate.html").then(function (res) {
        resolve({
            template: res.body,
            data: function () {
                return {
                    message: "123"
                }
            }
        })
    })
})

 

完美解决~

不过,仍是推荐使用 webpack 的 vue-loader。

X-Templates

一种比较优雅的模板加载方式。在JavaScript里面使用text/x-template类型,并指定一个id

可是这种加载方式至关于跟组件进行隔离了。因此要谨慎使用

<div id="watch-example">
        <hello-world></hello-world>
    </div>
    <script type="text/x-template" id="hello-world-template">
        <p>Hello World</p>
    </script>
    <script type="text/javascript">
        Vue.component("hello-world",{
            template:"#hello-world-template"
        })
        var vm = new Vue({
            el: "#watch-example"
        })
    </script>

v-once静态组件

若是组件中包含大量静态内容,能够考虑使用v-once将渲染结果缓存起来

Vue.component('terms-of-service', {
  template: '\
    <div v-once>\
      <h1>Terms of Service</h1>\
      ... a lot of static content ...\
    </div>\
  '
})

过分效果

Vue在插入、更新或移除DOM时,提供多种不一样方式的应用过分效果。包括如下工具

  • 在CSS过分和动画中自动应用CSS
  • 能够配合使用第三方CSS动画库,如Animate.css
  • 在过分钩子函数中使用Javascript直接操做Dom
  • 能够配合使用第三方Javascript动画库,如Velocity.js

单元素/组件的过分

Vue提供了 transition 的封装组件,在下列状况下能够给任何元素和组件添加 entering(进入)/leaving(离开)过分

  • 条件渲染(使用 v-if)
  • 条件展现(使用 v-show)
  • 动态组件
  • 组件根节点

例以下面例子

<style type="text/css">
        .fade-enter-active,
        .fade-leave-active {
            transition: opacity .5s
        }
        
        .fade-enter,
        .fade-leave-active {
            opacity: 0
        }
    </style>

<div id="demo">
        <button v-on:click="show = !show">Toggle</button>
        <transition name="fade">
            <p v-if="show">hello</p>
        </transition>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#demo",
            data: {
                show: true
            }
        })
    </script>

元素封装成过分组件以后,在遇到插入或删除时,Vue将

  1. 自动嗅探目标元素是否有CSS过分或动画,并在合适时添加/删除CSS类名
  2. 若是过分组件设置了过分的JavaScript钩子函数,会在相应的阶段调用钩子函数
  3. 若是没有找到Js钩子函数而且也没有检测到CSS过分/动画,DOM操做当即执行

过分-CSS-类名

有4个CSS类名在enter/leave的过分中切换

  1. v-enter:定义进入过分的开始状态,在元素被插入时生效,在下一帧移除
  2. v-enter-active:定义进入过分的结束状态,在元素被插入时生效,在过分/动画完成后移除
  3. v-leave:定义离开过分的开始状态,在离开过分被触发时生效,在下一帧移除
  4. v-leave-active:定义离开过分的结束状态,在离开过分被触发时生效,在过分/动画完成后移除

这些在enter/leave的过分中切换的类名,v-是这些类名的前缀。使用<transition name="my-transion">

能够重置前缀,好比v-enter替换为my-transition-enter

v-enter-active 和 v-lelave-active能够控制 进入/离开 过分的不一样阶段

CSS过分

经常使用的过分都是CSS过分。下面是一个简单的例子

<div id="demo">
        <button @click="show = !show">Toggle</button>
        <transition name="fade">
            <p v-if="show">hello</p>
        </transition>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#demo",
            data: {
                show: true
            }
        })
    </script>

<style type="text/css">
        .fade-enter-active{
            transition: all 3s ease;
        }
        .fade-leave-active{
            transition: all 8s linear;
        }
        .fade-enter, .fade-leave-active{
            transform: translateX(100px);
            opacity: 0;
        }
    </style>

CSS动画

CSS动画用法和过分相似,区别是在动画中v-enter类名的节点插入DOM后不会当即删除。

而是在触发animationend事件时删除。下面是一个动画效果的例子

<style type="text/css">
        @keyframes bounce-in {
            0% {
                transform: scale(0);
            }
            50% {
                transform: scale(1.5);
            }
            100% {
                transform: scale(1);
            }
        }
        
        @keyframes bounce-out {
            0% {
                transform: scale(1);
            }
            50% {
                transform: scale(1.5);
            }
            100% {
                transform: scale(0);
            }
        }
        
        .fade-enter-active {
            animation: bounce-in .5s;
        }
        
        .fade-leave-active {
            animation: bounce-out .5s;
        }
    </style>

自定义过滤类名

能够经过如下特征来自定义过分类名

  • enter-class
  • enter-active-class
  • leave-class
  • leave-active-class

这些特效的优先级高于普通类名。对于使用第三方过分系统和第三方CSS动画库十分有效。

下面代码使使用,Animate.css 结合使用

<div id="demo" style="margin-left: 50px">
        <button @click="show = !show">Toggle</button>
        <transition name="fade" 
            enter-active-class="animated tada" 
            leave-active-class="animated bounceOutRight"> 
            <p v-if="show">hello</p>
        </transition>
    </div>

JavaScript钩子

能够在属性中声明JavaScript钩子

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"
  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

--------------------------------------------------------------------
// ... methods: { // -------- // 进入中 // -------- beforeEnter: function (el) { // ... }, // 此回调函数是可选项的设置 // 与 CSS 结合时使用 enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave: function (el) { // ... }, // 此回调函数是可选项的设置 // 与 CSS 结合时使用 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } }

这些钩子函数能够结合CSS transitions/animations 使用,也能够单独使用

在 enter 和 leave中,回调函数 done 是必须的。不然他们会被同步调用,过分会当即完成

对仅使用JavaScript过分元素添加 v-bind:css="false",Vue会跳过CSS检测。

使用Velocity.js的简单例子

<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="example-4">
  <button @click="show = !show">
    Toggle
  </button>
  <transition
    v-on:before-enter="beforeEnter"
    v-on:enter="enter"
    v-on:leave="leave"
    v-bind:css="false"
  >
    <p v-if="show">
      Demo
    </p>
  </transition>
</div>
new Vue({
  el: '#example-4',
  data: {
    show: false
  },
  methods: {
    beforeEnter: function (el) {
      el.style.opacity = 0
      el.style.transformOrigin = 'left'
    },
    enter: function (el, done) {
      Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
      Velocity(el, { fontSize: '1em' }, { complete: done })
    },
    leave: function (el, done) {
      Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 })
      Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
      Velocity(el, {
        rotateZ: '45deg',
        translateY: '30px',
        translateX: '30px',
        opacity: 0
      }, { complete: done })
    }
  }
})

其余更多的渲染效果。查看如下连接

https://cn.vuejs.org/v2/guide/transitions.html#初始渲染的过渡

单文件组件(node.js)

在许多Vue项目中,使用Vue.component 来定义全局组件,紧接着用new Vue在每一个页面指定一个容器元素

  • 全局定义:强制要求每一个component中的命名不得重复
  • 字符串模板:缺少语法高亮,在HTML多行时,还须要 \
  • 不支持CSS:HTML和JS组件化时,CSS被遗漏
  • 没有构建步骤:限制只能使用HTML和ES5,不能使用预处理器

.vue 的单文件组件能够解决以上问题。而且还可使用Webpack 或 Browserify。

下面就是 .vue的单文件组件 示例。能够得到:完整语法高亮,CommonJS模块,组价化CSS

<template>
    <p>{{greeting}} World!</p>
</template>
<script>
    module.exports = {
        data: function () {
            return {
                greething: "Hello"
            }
        }
    }
</script>
<style scoped>
    p {
        font-size: 2em;
        text-align: center;
    }
</style>

有了 .vue 组件,咱们就进入了高级JavaScript应用领域。须要学习一些工具的使用

Node Package Manager(NPM):https://docs.npmjs.com/getting-started/what-is-npm  会操做就能够

Modern JavaScript with ES6:https://babeljs.io/docs/learn-es2015/ 

学习完这些工具后,咱们就能够进行webpack2教程了

webpack2:https://doc.webpack-china.org/

vue-loader : https://lvyongbo.gitbooks.io/vue-loader/content/?q=

vue-loader实例:https://sally-xiao.gitbooks.io/book/content/index.html

Vue-loader

vue-loader 是Webpack的加载器,能够将.vue后缀的单文件组件转换成纯Javascript模块

vue-loader提供不少很是酷炫的功能

  • 默认启用ES2015(ES6的另外一个称呼)
  • 容许为Vue组件的每一个部分使用其余Webpack装载程序,
  • 容许.vue文件中可应用自定义加载程序链的自定义部分
  • 处理在引用中的静态资源<style>和<template>做为模块依赖项,并用webpack加载他们
  • 能够模拟每一个组件的做用域CSS
  • 支持在开发过程当中组件热加载

简而言之,webpack和vue-loader的组合,提供了一个现代、灵活而且很是强大的前端工做流程

什么是Webpack?

参考资料:http://www.cnblogs.com/chenxygx/p/5126539.html

Vue组件规格

一个*.vue文件是使用HTML的语法描述Vue组合而成的自定义文件格式。每一个*.vue文件有三种类型的顶层语言块

<template>、<script>、<style>。和任选的附加自定义块。例如:

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style>
.example {
  color: red;
}
</style>

<custom1>
  This could be e.g. documentation for the component.
</custom1>

vue-loader将解析文件,提取每个语言块。经过装载器加载,最后组装回一个CommonJS模块

module.exports 是一个Vue.js 组件选项对象

vue-loader经过lang语言指定属性支持非默认语言,例如

<style lang="sass">
  /* write SASS! */
</style>

语言块 

<template>

默认语言:htmll

每一个*.vue文件最多能够包含一个<template>块

内容将做为字符串提取,并用做template编译的Vue组件的选项

<script>

默认语言:js

每一个*.vue文件最多能够包含一个<script>块

该脚本在相似CommonJS的环境中执行,可使用require() 其余依赖项,而且支持ES6

脚本必须导出Vue.js组件选项对象,Vue.extend() 也支持导出建立的扩展构造函数

<style>

默认语言:css

<style>单个*.vue文件中支持多个标签

一个<style>标签能够有scoped和module属性

默认状况下,内容将被提取并<head>做为实际<style>标记动态插入 。

也能够经过配置 Webpack 使组件内全部样式提取到一个CSS文件中。

自定义块 

vue-loader 10.2.0 中支持

*.vue对于任何项目特定须要,能够在文件中包含其余自定义快,例如<doce>

vue-loader将使用标签名称来查找应将那些webpack加载器应用于该部分的内容

应在选项loaders部分中vue-loader指定webpack装载程序

Src Imports

若是但愿将组件拆分红多个文件,可使用src属性为语言块导入外部文件

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

须要使用./进行相对路径定位,获取从已安装的npm包中导入

<style src="todomvc-app-css/index.css">

注释

在每一个语言块中,使用该语言的注释方法。对于顶级注释,使用HTML注释语法

<!-- comment contents here -->

项目设置

使用vue-cli

建立项目的时候,推荐使用脚手架工具,能够用 vue-loader 和 vue-cli,命令以下

npm install -g vue-cli
vue init webpack-simple hello-vue
cd hello-vue
npm install
npm run dev # 一切就绪!

解释一下:

全局安装vue-cli

vue init <template-name> <project-name>。目前可使用的模板有如下几种。

  1. browserify:全功能的Browserify + vueify。包括热加载、静态检测、单元测试
  2. browserify-simple:一个简易的Browserify + vueify,以便于快速开始
  3. webpack:全功能的webpack + vueify,包括热加载、静态检测、单元测试
  4. webpack-simple:一个建议的webpack + vueify,以便于快速开始

使用npm run dev,能够运行项目。在项目路径下,执行 webpack 可打包相关项目

而后就能够用IIS部署访问了

ES2015

当vue-loader 检测到 babel-loader 或者 buble-loader 在项目中存在时

将会用它们处理全部*.vue文件的<script>部分,因此,咱们就可使用Vue组件中的ES2015

学习笔记:http://www.cnblogs.com/chenxygx/p/6509564.html

一个引用其余Vue组件的,经典模式代码示例以下

<script>
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

export default {
  components: {
    ComponentA,
    ComponentB
  }
}
</script>

使用ES2015精简语法定义子组件。ComponentA Vue会自动转为component-a。

因此就能够在模板中引用组件<component-a>

转换正常*.js文件

因为vue-loader只能处理*.vue文件,须要在配置文件中告诉Webpack用babel-loader或者buble-loader

可使用vue-cli 脚手架工具建立

Scoped CSS

当<style>标签有scoped属性的时候(<style scoped>),它的CSS只能做用于当前做用域。

会由PostCSS转义成以下格式

//before
<style scoped> .example
{ color: red; } </style> <template> <div class="example">hi</div> </template>
//after
<style>
.example[_v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" _v-f3f3eg9>hi</div>
</template>
  • 同一个组件能同时拥有做用域和无做用域的样式
  • 父组件有做用域的CSS会影响到子组件
  • 有做用域的样式对其余部分没有影响

PostCSS

任何经过 vue-loader 处理过的CSS都在用PostCSS 重写有做用域限制的CSS部分。

你也能添加自定义的PostCSS插件处理。例如:autoprefixer 或 CSSNext

// webpack.config.js
module.exports = {
  // 其余配置...
  plugins: [
    new webpack.LoaderOptionsPlugin({
      vue: {
        // 使用用户自定义插件
        postcss: [require('postcss-cssnext')()]
      }
    })
  ]
}

热加载

当你启用热加载功能,编写完 *.vue 文件后,组件的全部实例对象被替换,而页面并无从新加载

仍然保持应用原有状态,这在你调整模板或修改组件样式的时候,大大改善了开发体验。

当使用 vue-cli 时,热加载自动启用

预处理器

在Webpack中,全部的预处理需须要和一个相应的加载器一同使用。

vue-loader 容许你用其它的Webpack 加载器去处理 Vue组件一部分代码。

会根据 lang 属性自动用适当的加载器去处理。

CSS

例如咱们编译用SASS编译<style>标签

npm install sass-loader node-sass --save-dev

<style lang="sass">
  /* 这里写一些 sass 代码 */
</style>

在引擎内部,首先<style>标签内的内容会被 sass-loader 编译,而后再被一步步处理。

Javascript

默认状况下,Vue组件内的全部Javascript会被babel-loader处理

npm install coffee-loader --save-dev

<script lang="coffee">
     # 这里写一些 coffeescript!
</script>

Templates

处理模板的过程有些不一样,由于大多数webpack模板加载器(例如:jade-loader),会返回一个模板处理函数

而不是被编译过的HTML字符,因此只须要安装 jade 便可

npm install jade --save-dev

<template lang="jade">
div
  h1 Hello world!
</template>

URL资源处理

vue-loader 能够自动用 css-loader 和Vue组件编译器来处理样式和模板文件。

在处理过程当中,全部的资源URL都会被当作依赖的模块来处理。例如:<img src=""> 被转移成 require("")

//原始
<img src="../image.png">

//转义
createElement('img', { attrs: { src: require('../image.png') }})

由于.png并非Javascript文件,须要配置webpack来使用file-loader和url-loader处理它们

使用脚手架工具 vue-cli 也能帮你配置这些。

file-loader 容许你指定在哪里复制和存放静态资源文件,用版本哈希值命名从而更好的利用缓存。

意味着能够把图片放到*.vue文件旁边,可以使用相对路径,而不须要担忧发布时候的URL。

使用适当的配置,webpack打包输出的时候,会自动把文件路径转为正确的URL

url-loader 容许你内联 base-64 数据格式的URL资源。能够减小HTTP请求小文件的数量

产品构建

当产品发布的时候,须要作两件事情

1.压缩应用的代码量

2.解决Vue.js源代码中的全部警告

实际上咱们须要的配置以下所示:

// webpack.config.js
module.exports = {
  // ... 其余选项
  plugins: [
    // Vue.js 代码报警告
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    // 清除无用代码来缩小代码量
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    // optimize module ids by occurence count
    new webpack.optimize.OccurenceOrderPlugin()
  ]
}

 

$

路由

大多数单页面应用,都推荐使用官方支持的vue-router库。更多细节能够看 vue-router文档

文档地址:http://router.vuejs.org/zh-cn/

单元测试

能够及使用Karma进行自动化测试。

文档地址:http://karma-runner.github.io/1.0/index.html

服务器渲染

$

相关文章
相关标签/搜索