VueJs学习笔记
特效库:TweenJS(补间动画库) VelocityJS(轻量级JS动画库) Animate.css(CSS预设动画库)
比较其他框架:https://cn.vuejs.org/v2/guide/comparison.html
Github:vue2-elm
安装
npm install vue
使用时推荐安装:Vue Devtools 可以方便调试 https://github.com/vuejs/vue-devtools#vue-devtools
安装命令行,快速搭建大型单页应用
npm install --g vue-cli
vue init webpack my-project
npm run dev
声明式渲染
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将
- 自动嗅探目标元素是否有CSS过度或动画,并在合适时添加/删除CSS类名
- 如果过度组件设置了过度的JavaScript钩子函数,会在相应的阶段调用钩子函数
- 如果没有找到Js钩子函数并且也没有检测到CSS过度/动画,DOM操作立即执行
过度-CSS-类名
有4个CSS类名在enter/leave的过度中切换
- v-enter:定义进入过度的开始状态,在元素被插入时生效,在下一帧移除
- v-enter-active:定义进入过度的结束状态,在元素被插入时生效,在过度/动画完成后移除
- v-leave:定义离开过度的开始状态,在离开过度被触发时生效,在下一帧移除
- 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>。目前可以使用的模板有以下几种。
- browserify:全功能的Browserify + vueify。包括热加载、静态检测、单元测试
- browserify-simple:一个简易的Browserify + vueify,以便于快速开始
- webpack:全功能的webpack + vueify,包括热加载、静态检测、单元测试
- 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
服务器渲染
$