1. 生命周期
我们先来看下图:
我们来解释一下上图的各个阶段:
beforeCreate: vue实例进行基础初始化时
created:实例初始化完成时
beforeMount:模板与数据结合挂载到页面之前
beforeUpdate:数据发生改变,但并未渲染之前
updated:数据发生改变,并渲染之后
mounted:页面挂载之后
beforeDestroy:组件销毁之前
destroyed:销毁组件之后
activated: keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。
deactivated:keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。
errorCaptured:2.5.0+ 新增,当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
2. computed计算属性
计算属性在computed:{}中声明,不需要在data中声明,当data中没有时会自动来计算属性中找。写法取下:
computer: {
aaa: {
get:function() {
// 读取该方法内容时
},
set:function(value) {
// 设置该方法时,即给该方法重新赋值时
}
}
3. 侦听属性
来看下watch的作用,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。来看演示代码:
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
4. 样式绑定
方法1: 对象形式
// 当isactive为true时存在active类名
<div v-bind:class="{ active: isActive }"></div>
// 传入多个class
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data: {
isActive: true,
hasError: false
}
// 绑定的数据对象不必内联定义在模板里:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
// 也可以在这里绑定一个返回对象的计算属性。
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
方法2: 数组形式
<div v-bind:class="[isactive]"></div>
data{
isactive:"active"
}
// 动态切换
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
// 在数组中加入对象语法
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
方法3: 绑定style样式
<div v-bind:style="styleObj"></div>
data{
styleObj:{
color:"black"
}
}
<div v-bind:style="[styleObj,{fontSize:'20px'}]"></div>
data{
styleObj:{
color:"black"
}
}
// 绑定多个值的数组,这样写只会渲染数组中最后一个被浏览器支持的值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
5. 条件渲染
5.1 v-if
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
如果想切换多个元素,我们使用template
包裹即可
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
vue会复用v-if中相同的组件,如果要避免,可设置key,如下:
<div v-if=“show”>
<input key=“username” />
</div>
<div v-else>
<input key=“password” />
</div>
5.2 v-show与v-if区别
- v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。
- v-show 不支持 <template> 元素,也不支持 v-else。
- v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
- v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
5.3 v-show与v-for一起使用
不推荐同时使用 v-if
和 v-for
。当 v-if
与 v-for
一起使用时,v-for
具有比 v-if
更高的优先级。
6. 列表渲染
6.1 数组的v-for
<ul id="example-2">
<li v-for="(item, index) in items" :key="item.id">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法,遍历没有in深,节省性能
6.2 对象的v-for
// 第二个参数为键名,第三个参数为索引
<ul id="v-for-object" class="demo">
<li v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。
6.3 注意事项
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
举个例子:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue
相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使用 vm.$set
实例方法,该方法是全局方法 Vue.set
的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
为了解决第二类问题,你可以使用 splice
:
vm.items.splice(newLength)
还有如下方法:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
6.4 对象更改检测注意事项
还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。例如,对于:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一个新的 age 属性到嵌套的 userProfile 对象:
Vue.set(vm.userProfile, 'age', 27)
你还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名:
vm.$set(vm.userProfile, 'age', 27)
有时你可能需要为已有对象赋予多个新属性,比如使用 Object.assign() 或 _.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
你应该这样做:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
6.5 显示过滤/排序结果
有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。
例如:
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个 method 方法:
<li v-for="n in even(numbers)">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
6.6 一段取值范围的 v-for
v-for
也可以取整数。在这种情况下,它将重复多次模板。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
结果:
1 2 3 4 5 6 7 8 9 10
6.7 v-for
on a <template>
类似于 v-if
,你也可以利用带有 v-for
的 <template>
渲染多个元素。比如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
6.8 v-for
with v-if
不推荐同时使用 v-if
和 v-for
。当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用,如下:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
上面的代码只传递了未完成的 todos。
而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if
置于外层元素 (或 <template>
)上。如:
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
6.9 一个组件的 v-for
在自定义组件里,你可以像任何普通元素一样用 v-for
。
<my-component v-for="item in items" :key="item.id"></my-component>
2.2.0+ 的版本里,当在组件中使用
v-for
时,key
现在是必须的。
然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props
:
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
不自动将 item
注入到组件里的原因是,这会使得组件与 v-for
的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。
下面是一个简单的 todo list 的完整例子:
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
>
<button>Add</button>
</form>
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
</div>
注意这里的 is="todo-item"
属性。这种做法在使用 DOM 模板时是十分必要的,因为在 <ul>
元素内只有 <li>
元素会被看作有效内容。这样做实现的效果与 <todo-item>
相同,但是可以避开一些潜在的浏览器解析错误。查看
Vue.component('todo-item', {
template: '
<li>
{{ title }}
<button v-on:click="$emit(\'remove\')">Remove</button>
</li>
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
7. 事件处理
7.1 ## 内联处理器中的方法
如果需要在内联语句处理器中访问原始的 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)
}
}
7.2 事件修饰符
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
v-on:click.prevent.self
会阻止所有的点击,而
v-on:click.self.prevent
只会阻止对元素自身的点击。
不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。
7.3 按键修饰符
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
你可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。
使用 keyCode
特性也是允许的:
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
-
.delete
(捕获“删除”和“退格”键) .esc
.space
.up
.down
.left
.right
有一些按键 (.esc
以及所有的方向键) 在 IE9 中有不同的 key
值, 如果你想支持 IE9,这些内置的别名应该是首选。
你还可以通过全局 config.keyCodes
对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
系统修饰键
2.1.0 新增
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
.meta
注意:在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。
例如:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
请注意修饰键与常规按键不同,在和 keyup
事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl
的情况下释放其它按键,才能触发 keyup.ctrl
。而单单释放 ctrl
也不会触发事件。如果你想要这样的行为,请为 ctrl
换用 keyCode
:keyup.17
。
.exact
修饰符
2.5.0 新增
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
鼠标按钮修饰符
2.2.0 新增
.left
.right
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
8. 组件
8.1
<table>
<tbody>
<tr is=“row”></tr>
<tr is=“row”></tr>
<tr is=“row”></tr>
</tbody>
</table>
vue.components('row',{
template:'<tr><td>this os a row</td></tr>'
})
因为h5有规定<tbody>
内只能写<tr>
,所以这里不能直接引用组件<row>
,要通过以上方式引用,<ul>
,<select>
同理,建议用is=“”写法
8.2 组件参数校验与非props特性
props:{
content:{
type: [String,Number],
required:true // 调用本组件的必传的属性
default: 123 // 默认值
validator: function(value) {
return value.length > 5 // 传入的内容长度必须大于5
}
}
}
非props特性,即父组件传递给子组件的参数并没有在子组件props中声明,此时该传递会出现该子组件最外层dom标签中,(如果是props特性,则dom中不显示 )如下:
<div content="hell">hello</div>
8.3 将原生事件绑定到组件
你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on
的 .native
修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
在有的时候这是很有用的,不过在你尝试监听一个类似 <input>
的非常特定的元素时,这并不是个好主意。比如上述 <base-input>
组件可能做了如下重构,所以根元素实际上是一个 <label>
元素:
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
这时,父级的 .native
监听器将静默失败。它不会产生任何报错,但是 onFocus
处理函数不会如你预期地被调用。
为了解决这个问题,Vue 提供了一个 $listeners
属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
有了这个 $listeners
属性,你就可以配合 v-on="$listeners"
将所有的事件监听器指向这个组件的某个特定的子元素。对于类似 <input>
的你希望它也可以配合 v-model
工作的组件来说,为这些监听器创建一个类似下述 inputListeners
的计算属性通常是非常有用的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` 将所有的对象合并为一个新对象
return Object.assign({},
// 我们从父级添加所有的监听器
this.$listeners,
// 然后我们添加自定义监听器,
// 或覆写一些监听器的行为
{
// 这里确保组件配合 `v-model` 的工作
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
现在 <base-input>
组件是一个完全透明的包裹器了,也就是说它可以完全像一个普通的 <input>
元素一样使用了:所有跟它相同的特性和监听器的都可以工作。
8.4 非父子组件间传值(bus/总线/观察者模式/发布订阅模式)
<div id="root">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
<script type="text/javascript">
Vue.protopyte.bus = new Vue()
Vue.component('child', {
props: {
content:String
},
template: '<div @click="childClick">{{content}}</div>',
methods:{
childClick: function() {
this.bus.$emit('change',this.content)
}
},
mounted: function() {
var self = this;
this.bus.$on('change',function(msg) { // 监听bus事件
})
}
})
</script>
8.5 在vue中使用插槽(slot)
// 父:
<child>
<p>内容</p>
</child>
// 子:
<div>
<slot>默认内容</slot>
</div>
// 父:
<child>
<div class=“header” slot=“header”></div>
<div class=“header” slot=“header”></div>
</child>
// 子:
<div>
<slot name=“header”></slot>
<div class=“content”>content</div>
<slot name=“footer”></slot>
</div>
// vue中的作用域插槽
<child>
<template slot-scope=“props”> /*template必须要加上,props为接收的子组件数据,名字可自定义*/
<li>{{props.item}}</li>
</template>
</child>
// 子组件
data: function(){
return {
list:[1,2,3,4]
}
}
<div>
<ul>
<slot v-for=“item of list” :item=item></slot>
</ul>
</div>
8.6 动态组件 & 异步组件
我们之前曾经在一个多标签的界面中使用 is
特性来切换不同的组件:
<component v-bind:is="currentTabComponent"></component>
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。例如我们来展开说一说这个多标签界面:
Posts Archive
- Cat Ipsum
- Hipster Ipsum
- Cupcake Ipsum
Click on a blog title to the left to view it.
你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent
实例。
重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive>
元素将其动态组件包裹起来。
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
来看看修改后的结果:
Posts Archive
- Cat Ipsum
- Hipster Ipsum
- Cupcake Ipsum
Click on a blog title to the left to view it.
现在这个 Posts 标签保持了它的状态 (被选中的文章) 甚至当它未被渲染时也是如此。你可以在这个 fiddle 查阅到完整的代码。
注意这个 <keep-alive>
要求被切换到的组件都有自己的名字,不论是通过组件的 name
选项还是局部/全局注册。
你可以在 API 参考文档 查阅更多关于 <keep-alive>
的细节。
加上exclude表示哪个组件不会被缓存
异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
如你所见,这个工厂函数会收到一个 resolve
回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason)
来表示加载失败。这里的 setTimeout
是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-async-component'], resolve)
})
你也可以在工厂函数中返回一个 Promise
,所以把 webpack 2 和 ES2015 语法加在一起,我们可以写成这样:
Vue.component(
'async-webpack-example',
// 这个 `import` 函数会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
当使用局部注册的时候,你也可以直接提供一个返回 Promise
的函数:
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
如果你是一个 Browserify 用户同时喜欢使用异步组件,很不幸这个工具的作者明确表示异步加载“并不会被 Browserify 支持”,至少官方不会。Browserify 社区已经找到了一些变通方案,这些方案可能会对已存在的复杂应用有帮助。对于其它的场景,我们推荐直接使用 webpack,以拥有内置的头等异步支持。
处理加载状态
2.3.0+ 新增
这里的异步组件工厂函数也可以返回一个如下格式的对象:
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
注意如果你希望在 Vue Router 的路由组件中使用上述语法的话,你必须使用 Vue Router 2.4.0+ 版本。
9. 动画
transition标签中不写name属性时默认类名前缀为v,否则为name定义的名字
9.2. 帧动画
自定义类名
通过自定义类名方式可使用animate.css库,如果想要使页面进入时也具有动画,需加入如下红框中的自定义类名
既有keyframe动画,又有transition动画,当两者动画时长不同时,通过设置type来规定用谁的动画时长,或自己设置。:duration=“1000”
也可以分别给入场,出场动画设置时长
:duration=“{enter:5000,leave:10000}”
9.3 vue引入velocity.js
入场动画
第一个是事件触发前
第二个是运行动画效果时
最后是动画完成后
动画完成后要执行done()函数,一定要调用
出场动画
多个元素时,同之前的组件复用,要想让其显示,需要加key
先显示,再隐藏
先隐藏,在显示,mode = “out-in”
动态组件除了用以上多个元素的方式还可用以下方式
列表过渡
transition-group相当于如下
9.4 动画封装
以下为用js,不用css的情况
9.5 引入swiper插件 vue-awesome-swiper
如果很多地方都需要用,就全局引入
因为style设置了scoped,所以在这里修改swiper内的样式是无效的,这时需要按以下设置来突破scoped
.wrapper >>> .swiper-pagination-bullet-active
background: #fff
窗口改变时swiper窗口重新计算
在Google 应用商店下载vue.js devtools插件工具
当图标超过8个时可以轮播,用计算属性处理数据
computed: {
pages () {
const pages = []
this.list.forEach((item, index) => {
const page = Math.floor(index / 8)
if (!pages[page]) {
pages[page] = []
}
pages[page].push(item)
})
return pages
}
}
10. 常用知识点
10.1. 路由跳转后页面滚动位置
10.2. 如果需要用ip地址访问,需要在pack.json文件的npm run dev中加上如下:
10.3. vue在atom中配置emmet
https://github.com/emmetio/emmet-atom/issues/364
点击文件 - 用户键盘映射打开配置文件
在配置文件的最后添加
'atom-text-editor[data-grammar~="vue"]:not([mini])':
'tab':'emmet:expand-abbreviation-with-tab'
注意: 如果配置文件中已经有'atom-text-editor[data-grammar~="vue"]:not([mini])':的其他配置, 那么要在其他配置的下面直接添加'tab': 'emmet:expand-abbreviation-with-tab', 而不能直接添加上面的两行, 不然会报错
重启编辑器
这样就可以愉快的玩耍了...
10.4 vue 使用clipboard实现复制功能
https://blog.csdn.net/guxuehua/article/details/79169190
10.5. vue星星评论插件
https://github.com/shengxinjing/vue-tiny-rate
原理:将一行有颜色的星星定位覆盖到无颜色的星星上,通过改变上层星星的width值来达到效果
10.6. promise封装jsonp
// 引入jsonp插件
import originJsonp from 'jsonp'
export default function jsonp(url, data, option) {
url += (url.indexOf('?') < 0 ? '?' : '&') + param(data) // 如果没有问号加问号,否则加&
return new Promise((resolve, reject) => {
originJsonp(url, option, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
export function param(data) {
let url = ''
for (var k in data) {
let value = data[k] !== undefined ? data[k] : ''
url += `&${k}=${encodeURIComponent(value)}` // encodeURIComponent 把字符串作为url组件进行编码
}
return url ? url.substring(1) : '' // 有data时删掉第一个&
}
10.7. Object.assign
// commonParams是一个对象
const data = Object.assign({}, commonParams, {// Object.assign 合并javascript对象
platform: 'h5', // h5平台
uin: 0, // qq号,默认0
needNewCode: 1
})
10.8 代理
在build目录下的webpack.dev.conf.js文件中,加入如下代码
const axios = require('axios')
const express = require('express')
const app = express()
var apiRoutes = express.Router()
app.use('/api', apiRoutes)
在devServer中加入
before(app) {
app.get('/api/getDiscList', function (req, res) {
var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
axios.get(url, {
headers: {
referer: 'https://c.y.qq.com/',
host: 'c.y.qq.com'
},
params: req.query //将参数返回给后端
}).then((response) => {
res.json(response.data)
}).catch((e) => {
console.log(e)
})
})
}
10.9 vue-lazyload插件
https://github.com/hilongjw/vue-lazyload
// 在main.js中引入
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad, {
loading: require('common/image/default.png')
})
// 使用方法,将需要的地方的 :src改为v-lazy即可
<img v-lazy="img.src" >
10.10 常用样式插件
import './assets/styles/reset.css' // 重置样式表
import './assets/styles/border.css' // 移动端1px像素问题
import FastClick from 'fastclick' //移动端点击300ms延迟问题
FastClick.attach(document.body);
10.11 建分支
在码云上建index-swiper分支,然后在本地
git pull
git checkout index-swiper
// 合并分支
git checkout master
git merge origin/index-swiper
git push
10.12 图片宽高自适应
overflow:hidden
width:100%
height:0
padding-bottom: 31.25%