前言
写这编文章也是为了回顾之前学的Vue,查漏补缺。此篇文章涵盖Vue的基本知识以及开发技巧等。这篇文章不讲Vue的相关原理,只会讲Vue 2.0在开发中常见的知识点。你准备好了吗?
安装
CDN引入
1 | <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> |
NPM
1 | npm install vue |
命令行工具(CLI)
安装Vue-cli npm install -g @vue/cli
利用脚手架创建一个Vue项目 vue create 项目名称
这是vue-cli3创建项目的命令;vue-cli2创建一个Vue项目 vue init webpack 项目名称
;
Vue实例
实例&&数据&&方法
当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
1 | var data = {a:1} |
当数据被Object.freeze()
时,这会阻止修改现有的 property,也意味着响应系统无法再追踪变化。
生命周期
beforeCreate:只是初始化一些生命周期函数和默认事件,其他的均未创建。
created:初始化data和methods了。
beforeMount:数据已经准备好了,还没渲染到页面。
mounted:将编译好的HTML挂载到页面,完成了渲染。
beforeUpdate:数据被修改,当是还没被重新渲染到页面。
updated:重新渲染页面,页面已经是修改后的了。
beforeDestroy:Vue实例进入销毁状态,data、methods,以及过滤器和指令都是可以用的。
destroyed:Vue实例已经被销毁。
看懂下面这张图就行
模板语法
插值
文本
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值。
1 | <span>Message: {{ msg }}</span> |
无论何时,绑定的数据对象上 msg property 发生了改变,插值处的内容都会更新。
通过使用 v-once
指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:
1 | <span v-once>这个将不会改变: {{ msg }}</span> |
原始HTML
1 | <p>Using v-html directive: <span v-html="rawHtml"></span></p> |
v-html
可能会引发XSS攻击,因此绝不要对用户提供的内容使用插值。
Attribute && 表达式
1 | <div v-bind:id="dynamicId"></div> |
指令
v-if
:判断true或者flase,是否插入元素。v-else
:经常和v-if
一起用,还有v-else-if
。v-for
:遍历循环,注意要绑定:key
。v-on
:处理事件,v-on:事件名="表达式||函数名"
,简写@事件名="函数名"
。v-bind
:绑定属性,v-bind:属性名="属性值"
简写:属性名="属性值"
。v-show
:原始的显示与隐藏,与v-if
不同,v-if
是插入元素或者删除元素,开销大。v-html
:插人原始HTML,插入的元素要用 >>>
css选择器渲染。v-text
:插入文本。v-cloak
:解决vue解析时出现页面闪烁问题。v-model
:双向数据绑定。
修饰符
@submit.prevent="fName"
:.prevent
阻止事件默认行为。@click.stop="fName"
:.stop
阻止事件冒泡,.capture
可以发生事件捕获,.self
只触发本身。@keyup.enter="fName"
:.enter
键盘回车事件,当然还有很多按键,请看我的另一篇文章Vue监听回车事件@keyup。@click.once="fName"
:.once
事件只触发一次。<el-input @keyup.enter.native="search"></el-input>
:.native
在自定义组件中,要加native
才能监听原生的事件。<input v-model.lazy="msg" >
:.lazy
惰性更新,也就是说不会更新那么快,等输入完成后才更新。<input v-model.trim="msg">
:.trim
去除前后空格。<input v-model.number="msg">
:.number
将输入的字符串变成数字。.sync
:对prop进行双向绑定,用法如下
1 | //父组件 |
.passive
:提升移动端的性能,大概解释就是每次滚动都会有一个默认事件触发,加了这个就是告诉浏览器,不需要查询,不需要触发这个默认事件。
利用vue中的修饰符能让你的开发事倍功半。
计算属性和侦听器
基础实例
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,所以,对于任何复杂逻辑,你都应当使用计算属性。
1 | <p>Reversed message: "{{ reversedMessage() }}"</p> |
1 | computed: { |
计算属性缓存 vs 方法
1 | // 在组件中 |
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
计算属性 vs 侦听属性
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
1 | //computed实现属性计算 |
计算属性的 setter
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
1 | computed: { |
监听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
除了 watch 选项之外,您还可以使用命令式的 vm.$watch。
Class 与 Style 绑定
绑定 HTML Class
对象语法
我们可以传给 v-bind:class 一个对象,以动态地切换 class:
1 | <div :class="{ active: isActive }" :class="classObject"></div> //两种形式 |
上面的语法表示 active 这个 class 存在与否将取决于数据 property isActive 的布尔值。
数组语法
1 | <div :class="[activeClass, errorClass]" :class="[isActive ? activeClass : '', errorClass]"></div> //也可以使用三元表达式 |
绑定内联样式
对象语法
1 | <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> |
数组语法
1 | <div v-bind:style="[baseStyles, overridingStyles]"></div> |
和绑定HTML Class 大同小异,这里就不做多描述了。
注意:当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS property 时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
前缀多重值
你可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,如下
1 | <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div> |
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。
条件渲染
1 | <div v-if="type === 'A'"> |
v-if
,v-else
,v-else-if
,v-for
,v-show
在前面的指令那里都有解释,这里就不做多描述了。
不推荐同时使用
v-if
和v-for
;当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
注意
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外。也就是说v-if
切换是,复用了已有元素。要用key 管理可复用的元素
。
列表渲染
在 v-for 里使用对象
1 | <div v-for="(value, name, index) in object"> |
在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。
维护状态
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:
1 | <div v-for="item in items" v-bind:key="item.id"> |
不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
数组更新检测
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括(可以改变原数组的方法):push
,pop
,shift
,unshift
,splice
,sort
,reverse
;
当然也可以使用数组替换,用新数组替换原来的旧数组,达到数据变化以驱动视图更新。例如 filter()
、concat()
和 slice()
,虽然不能改变原数组,但是可以赋值替换的方式来改变原数组。
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。
在 v-for 里使用值范围
v-for 也可以接受整数。在这种情况下,它会把模板重复对应次数。
1 | <div> |
事件处理
可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
1 | <button v-on:click="greet">Greet</button> |
除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:
1 | <button v-on:click="say('hi')">Say hi</button> |
事件修饰符,在前面有说了,这里就不做多描述。
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
1 | <!-- 即使 Alt 或 Shift 被一同按下时也会触发 --> |
鼠标按钮修饰符.left
,.right
,.middle
;
表单输入绑定
基础用法
v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源,v-model是双向数据绑定的;
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用 value property 和 input 事件;
- checkbox 和 radio 使用 checked property 和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
绑定文本:<input v-model="message" >
多行文本:<textarea v-model="message" ></textarea>
复选框:<input type="checkbox" v-model="checked">
单选框:选择框:1
2<input type="radio" id="one" value="One" v-model="picked">
<input type="radio" id="two" value="Two" v-model="picked">1
2
3
4
5
6<select v-model="selected" multiple> //如果可以多选,加上multiple
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>值绑定
1
2
3
4
5
6
7
8
9
10<!-- 当选中时,`picked` 为字符串 "a" -->
<input type="radio" v-model="picked" value="a">
<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle">
<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>修饰符
.trim
,.lazy
,number
;在模板语法里面有讲解了,这里就不做多描述。组件
组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。 - (单个根元素)*示例:
1
2
3
4
5
6
7
8
9// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})组件复用
你可以将组件进行任意次数的复用:注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。组件之间是独立的,复用的时候也会产生独立的作用域。1
2
3
4
5<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div> - data 必须是一个函数*
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:这也就是为什么,组件复用的时候,复用组件之间的数据是不互通的,作用域相互独立。1
2
3
4
5data: function () {
return {
count: 0
}
}
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册
和局部注册
。至此,我们的组件都只是通过Vue.component
全局注册的:组件通信
父向子传props:子传父$emit:1
2
3
4
5
6
7//...父组件
<son :title="hello" ></son>
//...
//...子组件
{{title}}
props:[title]
//...
子组件通过$emit
触发父组件的事件,而达到数据传递的效果。EventBus 事件总线传递数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//...父组件
<son @getSonData="sonData" ></son>
methods:{
sonData(data){
console.log(data) //data为子组件传递过来的数据
}
}
//...
//...子组件
<button @click="sendData">向父组件传数据</button>
methods:{
sendData(){
this.$emit('getSonData','我是子组件传递过来的数据')
}
}
//...
…在组件上使用v-model
等价于1
<input v-model="searchText">
当用在组件上时,v-model 则会这样:1
2
3
4<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>为了让它正常工作,这个组件内的 必须:1
2
3
4<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input> - 将其 value attribute 绑定到一个名叫 value 的 prop 上
- 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出。
写成代码之后是这样的:现在 v-model 就应该可以在这个组件上完美地工作起来了:1
2
3
4
5
6
7
8
9Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})1
<custom-input v-model="searchText"></custom-input>
通过插槽分发内容:
和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:
1 | <alert-box> |
幸好,Vue 自定义的 <slot>
元素让这变得非常简单:
1 | Vue.component('alert-box', { |
动态组件
有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:
上述内容可以通过 Vue 的
1 | <!-- 组件会在 `currentTabComponent` 改变时改变 --> |
在上述示例中,currentTabComponent 可以包括:已注册组件的名字,或一个组件的选项对象
解析 DOM 模板时的注意事项
有些 HTML 元素,诸如 <ul>
、<ol>
、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>
、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
1 | <table> |
这个自定义组件 <blog-post-row>
会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:
1 | <table> |
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
字符串 (例如:template: '...')
单文件组件 (.vue)
<script type="text/x-template">
写在最后
Vue的基础篇就到这里结束,下篇深入了解组件。