一、什么Vue
1、Vue的特点:
- 遵循 MVVM 模式。
- 编码简洁,体积小,运行效率高,适合移动/PC端开发。
- Vue本身只关注 UI ,可以轻松引入Vue插件和其它第三库开发项目。
2、Vue与其他前端 JS 框架关联
- 借鉴 angular 的 模板 和 数据绑定 技术。
- 借鉴 react 的 组件化 和 虚拟DOM 技术。
3、什么是 MVVM 模型
4、Vue是如何实现动态数据绑定的
- 当页面(V 模型)数据发生变化(比如:文本框用户输入的内容发生变化),此时会文本框会有一个 DOM 监听函数( VM 模型 在渲染页面时自动添加的 DOM Listeners)。
- 执行监听函数将内容重新更新到(M 模型 data)内存中。
- 而再次将内容渲染到页面(V 模型)上时,使用到 VM 模型中的 Data Bindings (数据绑定)从内存中取出利用 虚拟DOM 操作渲染到页面中。
注:
- 对于需要使用输入法 (如中文、日文、韩文等) 的语言, v-model 不会在输入法组合文字过程中得到更新。
- 如果想处理这个过程,请使用 input 事件
二、Vue 的生命周期
Vue 生命周期主要分为三部分: 初始化阶段,更新阶段,销毁阶段
(1)初始化阶段
- new Vue() -> befreCreate 生命函数
- 准备工作(Observe Data 给属性添加set方法,用于监视属性 init Events 初始化事件)
- Createed 生命函数
- 判断 el是否存在( 存在,自动将页面挂载到 Vue 实例上,不存在,后期可以手动挂载挂载 vm.$mount(el) )
- 判断是否有 template 选项
(没有 则编译解析 el 内部的模板的一些语法
【在内存中批量去替换一些语法,在一次性将模板放回,等待一次性更新页面】 ) - beforeMount 生命函数 -> 一些操作 -> mounted 生命函数
(2)更新阶段
- beforeUpdate 生命函数 -> 更新页面 -> updated 生命函数
(3)销毁阶段(当调用 vm.$destroy() 时)
- beforeDestroy 生命函数 -> 一些操作 -> destroyed
三、HelloWord
<div id="app">
<p>{{msg}}</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "Hello World",
},
});
</script>
四、模板语法
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
1、双括号表达式
<p>{{msg}}</p>
<p>{{msg.toUpperCase()}}</p>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: `<a href="www.baidu.com">跳到百度</a>`
},
});
</script>
注:
- v-once 指令也能执行一次性地插值,当数据改变时,插值处的内容不会更新。
<p v-once>这个将不会改变: {{ msg }}</p>
- 在 Vue 解析前,在页面显示的是双括号,而无法将数据显示出来。
2、v-text 和 v-html 指令
<p v-text="msg"></p>
<p v-html="msg"></p>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: `<a href="www.baidu.com">跳到百度</a>`
},
});
</script>
两者的区别:
命令 | 解释 |
---|---|
v-text | 不会对内容进行转义,类似于 textcontent |
v-html | 会对内容进行转义,类似于 innerhtml |
3、强制数据绑定
<img :src="imgUrl" />
<img v-bind:src="imgUrl" />
<script>
const vm = new Vue({
el: "#app",
data: {
imgUrl: `https://cn.vuejs.org/images/logo.png`,
}
});
</script>
注:
- 如果绑定的 attribute 值为 null、undefined 或 false, attribute 不会被包含在渲染出来的 DOM 标签上。
4、事件监听
<button v-on:click="test1">监听一</button>
<button @click="test2">监听二</button>
<script>
const vm = new Vue({
el: "#app",
methods: {
test1() {
alert("test1");
},
test2() {
alert("test2");
},
},
});
</script>
五、计算属性和监视
<div id="app">
<label for="xin">姓</label>
<input type="text" id="xin" v-model="firstName" /><br />
<label for="ming">名</label>
<input type="text" id="ming" v-model="lastName" /><br />
<label for="xinming1">姓名1(单向)</label>
<input type="text" id="xinming1" v-model="fullName1" /><br />
<label for="xinming2">姓名2(单向)</label>
<input type="text" id="xinming2" v-model="fullName2" /><br />
<label for="xinming3">姓名3(双向)</label>
<input type="text" id="xinming3" v-model="fullName3" /><br />
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
firstName: "A",
lastName: "B",
fullName2: "A" + " " + "B",
}
});
</script>
1、实现单向数据绑定
- 方法一: 利用计算属性
在 computed 属性对象中定义计算属性的方法在页面中使用{{方法名}}来显示计算结果。
<script>
const vm = new Vue({
computed: {
fullName1() {
return this.firstName + " " + this.lastName;
},
},
});
</script>
注:
- 如果单独修改 fullName1 的值,是不会影响 fullName1 的值,还是原来的值( firstName + lastName)。
- 方法二: 利用属性监听 watch
通过 vm 对象的 $watch() 或 watch 配置来监视指定的属性,当属性变化时,回调函数自动调用,在函数内部进行计算。
<script>
const vm = new Vue({
watch: {
firstName: function (newVal, oldVal) {
return newVal + " " + this.lastName;
},
});
//使用 API 方法
vm.$watch("lastName", function (newVal, oldVal) {
return this.firstName + " " + newVal;
});
</script>
computed 和 watch 的区别
方法 | 解释 |
---|---|
computed | 初始化和计算的多个属性值只要至少一个发生改变时执行该函数 |
watch | 当监听的属性发生改变时执行该函数 |
注意细节
-
在 computed 中的语法规则:函数名必须是绑定属性值的名称。并且该属性在 data 中可以不定义。 其他情况在 data 中必须定义。
-
在 watch 中的语法规则:属性名 : 函数 。
-
computed 计算出来的属性值是放在缓存中的,具体看下面案例
<div id="app">
<label for="xin">姓</label>
<input type="text" id="xin" v-model="firstName" /><br />
<label for="ming">名</label>
<input type="text" id="ming" v-model="lastName" /><br />
<label for="xinming1">姓名1(单向)</label>
<input type="text" id="xinming1" v-model="fullName1" /><br />
<p>{{fullName1}}</p>
<p>{{fullName1}}</p>
<p>{{fullName1}}</p>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
firstName: "A",
lastName: "B",
fullName2: "A" + " " + "B",
},
computed: {
fullName1() {
console.log("被调用");
return this.firstName + " " + this.lastName;
},
},
});
</script>
很明显调用该函数是在初始化执行的,然后将结果存放在缓存中。因此可以得到一个结论:当获取数据时,会先向缓存中找是否有该属性的值。
2、实现双向绑定(高级)
<script>
const vm = new Vue({
computed: {
fullName3: {
get() {
return this.firstName + " " + this.lastName;
},
set(value) {
const name = value.split(" ");
this.firstName = name[0];
this.lastName = name[1];
}
}
}
});
</script>
- 利用了回调函数的机制,将属性值进行修改,进而触发了 Vue 的双向数据绑定。
3、什么是回调函数
- 开发者定义的函数。
- 开发者并没有执行该函数。
- 但最终该函数执行了。
六、class 和 style 绑定
1、 class 绑定(三种方法)
- 字符串形式
<style>
.aClass{
color: yellow;
}
.bClass{
color: red;
}
</style>
<p :class="a">字符串</p>
<button @click="update">更新</button>
<script>
const vm = new Vue({
el: '#app',
data: {
a: 'aClass'
},
methods: {
update(){
this.a = 'bClass',
}
},
})
</script>
- 对象形式
<style>
.aClass{
color: yellow;
}
.bClass{
color: red;
}
</style>
<p :class="{aClass:isA,bClass:isB}">对象</p>
<button @click="update">更新</button>
<script>
const vm = new Vue({
el: '#app',
data: {
isA: true,
isB: false,
},
methods: {
update(){
this.isA = false,
this.isB = true,
}
},
})
</script>
- 数组形式
<style>
.aClass{
color: yellow;
}
.bClass{
color: red;
}
</style>
<p :class="['aClass', 'bClass']">数组</p>
2、style 绑定(一种方法)
<p :style="{color: activeColor, fontSize: fontSize + 'px'}">style 绑定</p>
<button @click="update">更新</button>
<script>
const vm = new Vue({
el: '#app',
data: {
isA: true,
isB: false,
},
methods: {
update(){
this.activeColor = 'yellow',
this.fontSize = 30,
}
},
})
</script>
七、条件渲染
1、v-if 和 v-else
<div id="app">
<p v-if="ok">成功</p>
<p v-else>失败</p>
<button @click="ok = !ok">更新</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
ok: true
}
})
</script>
2、v-show
<div id="app">
<p v-show="ok">成功</p>
<p v-show="!ok">失败</p>
<button @click="ok = !ok">更新</button>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
ok: true
}
})
</script>
3、v-if 和 v-show 两者的区别:
- v-if 该值为 false 时,则该 DOM 会从 DOM 树中移除,即从内存中移除。
- v-show 该值为false 时,则会添加样式 display:none; 从而达到移除效果。
另外:
- v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
- v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- 而 v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
小细节:
- 如果使用 v-if 来控制多个 DOM 元素,可以将多个元素放在 template 标签中,v-if 也放在此标签中,在页面显示上此标签会隐藏。
- v-show 不支持 template 标签,也不支持 v-else。
八、列表渲染 v-for
1、渲染、更新、删除列表
<ul>
<li v-for="(p, index) in persons" :key="index">
{{index}} --- {{p.name}} --- {{p.age}}
---<button @click="deleteP(index)">删除</button>
---<button @click="updateP(index,{name:'Cat', age:70})">更新</button>
</li>
</ul>
<script>
const vm = new Vue({
el: "#app",
data: {
/*
vue 本身只是监视了 persons 的变化,没有监视数组内部数据的变化
vue 重写了数组中的一系列改变数组内部的方法(先调用原生,更新界面)
---> 数组内部发生改变,界面自动更新
*/
persons: [
{ name: "Tom", age: 18 },
{ name: "Jack", age: 13 },
{ name: "Bob", age: 12 },
{ name: "Rose", age: 15 },
],
},
methods: {
deleteP(index) {
this.persons.splice(index, 1);
},
updateP(index, newP) {
// 并没有改变 person 本身,数组内部发生了变化,但并没有调用变异方法,vue 不会更新界面
// this.persons[index] = newP
this.persons.splice(index, 1, newP);
//增加
//this.persons.splice(index, 0, newP);
},
},
});
</script>
注:Vue 之所以能够在更新、删除、添加数组内容时,重新渲染页面主要在以下下面几点
- Vue 本质上是监听数组或者对象数据结构,而不是监听数据内容及数量的变化。
- 至于为什么在更新、删除、添加数组内容时,Vue 能够重新渲染页面,是在于 Vue 内部重新编写原生方法。
- 原理: vue 重写了数组中的一系列改变数组内部的方法(先调用原生,更新界面)
导致数组内部发生改变,界面自动更新。
另外:
- filter()、concat() 和 slice() 它们不会变更原始数组,而总是返回一个新数组。
- 因此、要实现修改原数组可以:可以用新数组替换旧数组( oldArray = newArray )
2、 渲染对象
<ul>
<li v-for="(value, key) in persons[1]" :key="key">
{{key}} --- {{value}}
</li>
</ul>
3、 列表排序及搜索
<li v-for="(p, index) in filterpersons" :key="index">
{{index}} --- {{p.name}} --- {{p.age}}
</li>
<button @click="setOrderType(1)">年龄升序</button>
<button @click="setOrderType(2)">年龄降序</button>
<button @click="setOrderType(0)">原本排序</button>
<script>
const vm = new Vue({
data: {
orderType: 0, // 0 代表原本 1代表升序 2代表降序
searchName: "",
},
methods: {
setOrderType(orderType) {
this.orderType = orderType;
},
},
computed: {
filterpersons: function () {
const { searchName, persons, orderType } = this;
let fPersons;
//过滤
fPersons = persons.filter((p) => p.name.indexOf(searchName) >= 0);
//排序
if (orderType !== 0) {
fPersons.sort(function (p1, p2) {
//返回负数,p1在前面。 返回正数,p2在前面。
if (orderType === 2) {
return p2.age - p1.age;
} else {
return p1.age - p2.age;
}
});
}
return fPersons;
},
},
})
</script>
注:
- v-for 也可以用在 template 标签上。
- v-for 和 v-if 可以一起共用。(v-for 在同一节点上优先级高于 v-if)
<!--部分项渲染节点-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
<!--有条件地跳过循环的执行-->
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
九、v-ref 指令 和 v-cloak 指令
1、v-ref 指令
- 获取标签的文本内容(前提是文本内容没有进行双向绑定时)可以使用 v-ref
<p ref="content">jiajia</p>
<button @click="hint">提示</button>
<script>
new Vue(
el: '',
methods: {
hint() {
/*
ref:指定唯一标识 vue 对象通过 $els 属性访问这个属性对象
this.$refs 获取的是 有 ref 属性的 DOM 标签的数组
this.$refs.content 获取 ref 属性值为 content的标签
*/
alert(this.$refs.content.textContent)
}
}
)
</script>
2、v-cloak
- 使用 v-cloak 前我们先看一个小案例
<div id="app">
<p>{{msg}}</p>
</div>
<script>
// 模拟先后端发请求时,出现延迟
alert('-------')
new Vue({
el: "#app",
data: {
msg: 'jiajia'
},
</script>
出现这个情况的主要原因是:后端时间延迟,导致 Vue 实例无法进行解析页面,从而表达式原样显示。
- 此时 v-cloak 指令就派上用场了,结合 css 样式,在关联实例结束编译前,将表达式进行隐藏。
- 这个指令保持在元素上直到关联实例结束编译。
<style>
[v-cloak] {
display: none;
}
</style>
<p v-cloak>{{msg}}</p>
十、自定义指令
需求:自定义2个指令
-
功能类似于v-text,但转换为全大写 v-upper-text
-
功能类似于v-text,但转换为全小写 v-lower-text
<div id="app1">
<p v-upper-text="msg1"></p>
<p v-lower-text="msg1"></p>
</div>
<div id="app2">
<p v-upper-text="msg2"></p>
<p v-lower-text="msg2"></p>
</div>
<script>
// 注册全局指令
Vue.directive("upper-text", function (el, binding) {
/*
el 指令属性所在的标签对象
binding 包含指令相关信息数据的对象
*/
el.innerHTML = binding.value.toUpperCase();
});
const vm1 = new Vue({
el: "#app1",
data: {
msg1: "haohAo",
},
// 局部指令
directives: {
'lower-text': function(el, binding) {
el.innerHTML = binding.value.toLowerCase();
}
}
});
const vm2 = new Vue({
el: "#app2",
data: {
msg2: "dhfeFROfd",
},
});
</script>
十一、事件处理
1、 监听获取原生 DOM 对象
<button @click="test3">test3</button>
<button @click="test4(123, $event)">test4</button>
<script>
const vm = new Vue({
el: "#app",
methods: {
// 默认传原生事件
test3(event) {
alert(event.target.innerHTML);
},
// 多个参数
test4(number, event) {
alert(event.target.innerHTML + number);
},
}
});
</script>
2、 阻止事件冒泡
<!-- 事件冒泡 停止冒泡 @click.stop-->
<div style="width: 200px; height: 200px; background: red" @click="test5">
<div style="width: 100px; height: 100px; background: blue"
@click.stop="test6"
></div>
</div>
3、 阻止事件的默认行为
<!-- 阻止事件的默认行为 .prevent-->
<a href="http://www.baidu.com" @click.prevent="test7">去百度</a>
4、按键监听
<h2>3、按键修饰符 (按下Enter抬起,读取内容).enter</h2>
<input type="text" @keyup.enter="test8" />
5、提交事件不再重载页面
<form v-on:submit.prevent="onSubmit"></form>
十二、表单数据收集
v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
- v-model 本质上是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用 value property和 input 事件 ;
- checkbox 和 radio 使用 checked property 和 change 事件;
- select 字段将 value 作为 prop 并将 change 作为事件。
1、文本框
<input type="text" name="" id="" v-model="userName">
2、多行文本
<textarea v-model="message" placeholder="add multiple lines"></textarea>
3、复选框
- 单个复选框
<input type="checkbox" id="checkbox" v-model="checked">
- 多个复选框(绑定到同一个数组)
<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>
<script>
new Vue({
el: '...',
data: {
checkedNames: []
}
})
</script>
4、单选按钮
<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>
<script>
new Vue({
el: '...',
data: {
picked: ''
}
})
</script>
5、选择框
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<script>
new Vue({
el: '...',
data: {
selected: ''
}
})
</script>
5、表单修饰符
- lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
- number
自动将用户的输入值转为数值类型
<input v-model.number="age" type="number">
- trim
自动过滤用户输入的首尾空白字符
<input v-model.trim="msg">