哈喽,今天不加班,回来整理一下以前的旧笔记,给你们分享一波基础知识
1.Vue模板的使用
<div id="app">
{{ msg }} //vue中的data又属性值
{{ 1+2+4*7/5 }}
{{ isShow?'真好看':'真丑' }}
{{ parseInt('10.2345') }}
</div>
- {{ }}里面可以写任意js表达式,变量,函数,属于js环境
- 如果里面写的变量,一般都是挂载在实例中的变量
- 如果里面写的是函数调用,那这个函数只能是Vue实例methods上的方法,但函数调用如果没有返回值,那么在模板中就不会渲染
2.Vue指令的使用
v-model
// 必须要注意,这是针对表单控件的指令,可以让表单内容和Vue的数据双向绑定
<label>请输入内容:</label>
<input type="text" v-model="text"> // 与Vue的data绑定
const vm = new Vue({
el:"#app",
data:{
text: '' // 这是input框输入的内容,可以使用模板在页面中打印出来
}
})
v-text
只能渲染内容,如果字符串中有标签,会把标签当作字符串一起渲染,类似于原生js中的innerText() 方法
v-html
// 用来渲染富文本数据,渲染内容包括内容和标签,相当于原生js中的innerHTML()方法
<div v-html="content"></div>
const vm = new Vue({
el:"#app",
data:{
content:`
<h1 style="color:red">我是富文本数据</h1>
`
}
})
v-bind
// 属性的动态绑定指令,很常用,使用后属性的属性值将不再是字符串,而是变量
<div id="app">
<div v-bind:id="a">等我打完</div>
<input type="text" v-model="imgUrl">
<img v-bind:src="imgUrl" alt=""> //内部是js环境,解析的是变量,不是字符串,如果不写: 那么解析的就是字符串了
</div>
const vm = new Vue({
el: "#app",
data:{
a: "box",
imgUrl: ""
}
})
:class="{}" / :class="[]"
// 通常是class和style使用的
// 当给class使用时,class的值可以是对象,也可以是数组,表示有多个类
<div id="app">
<div
v-for="(item,index) in arr"
key= "item.index"
@click="testClick(index)"
:class="{num === index?active:''}"></div>
</div>
const vm = new Vue({
el: '#app',
data: {
arr: [1,2,3,4,5,6],
num: 0 // 默认值是0,表示下标为0的div的类名是active,其他没有active的类名
},
methods: {
textClick(i){
this.num = i //每当点击当前的的div是,对应的下标i将赋值给num,只要满足num === index ,那么active就是当前div的类名
}
}
})
// 当class的值是数组时,数组的每个元素都是该div的类名
<div :class="['active','isShow','isNumber']"></div>
=>
<div class="active isShow isNumber"></div>
:style="{}"
<div :style="{
width: 100+200+'px',
height: 1>2?'400px':'300px',
background:color
}">11</div>
<!-- 借此成 宽300高300背景红色div -->
/*
:style=""
{}
对象键css样式
值可以是表达式,可以是变量
*/
3. MVVM原理
这就是Vue双向绑定的原理,改变数据,视图刷新
- M 数据
- V 视图
- mv => 数据改变视图自动刷新
- vm => new Vue实例
主要三个阶段
1. 创建阶段
new实例中的data数据对象创建时,vue会自动遍历
在遍历的时候,会使用Object.defineProperty中的setter/getter拦截每个对象的属性,
当data数据改变,vue中的setter触发
同时,会触发一个观察者watcher,setter和watcher一起触发回调函数render
2. 生成虚拟dom阶段
回调函数中的render函数,作用渲染虚拟dom,
3. 同步和渲染阶段
每次data数据改变时,都会有一次虚拟dom的类比较,当前的虚拟dom会在先前保存在内存中的虚拟dom比较
通过key属性,每层对应查找key值,发现没有key值,则会替换掉
比较出不同后新的虚拟dom节点会替换旧的,并储存在内存中
4.监听器
监听data的变量或对象属性值,只要改变了,就执行方法
<div id="app">
<div @click="textWatch">
{{obj.a}}
</div>
</div>
const vm = new Vue({
el: '#app',
data: {
obj: {
a: 1,
b: 2
}
},
watch: {
obj.a: {
handler(newVal,oldVal){
// 开始监听对象a的属性值
// newVal 表示改变后a的值,oldVal 表示原始a的值
...
}
},
obj: {
deep: true
// 深度监听,监听对象必须要使用deep,否则监听不到
immediate: true
// 表示页面渲染时是否立马监听
handler(newVal,oldVal){
...
}
}
}
methods: {
textWatch(){ // 用来改变对象属性值的事件
this.obj.a = -1
}
}
})
# 常用小伙伴分不清computed和watch的区别,我来给你们分析一下
/*
watch属于异步操作,只要监听的目标数据发生改变,就会触发watch中的方法,否则永不触发
computed属于同步操作,这是依赖于data数据的属性,如果你要用到的一个数据基于data数据,则可以将其放在computed中,
computed: {
testData: ()=>{ // 记住testData变量不能定义在data中,因为变量不能重复定义
return obj.a += 1
}
}
*/
算了,干脆直接另起一个小目录,computed这个也很重
// computed是基于响应式数据依赖的缓存的一个`值`
// 说的很明了,computed返回的是一个值,computed返回的值会缓存
<div id="app">
{{ num }}
{{ doubleNum }}
<button @click="change">改变计算属性 </button>
</div>
const vm = new Vue({
el: '#app',
data:{
num: 2
},
methods: {
change(){
this.doubleNum = 100;
}
},
computed: {
doubleNum: { // get和set必须成对出现
get(){ // 可以利用其他数据的值赋值给计算数据的属性
return this.num*4 // 此时doubleNum等于400
},
set(val){ // 拦截计算属性的值并修改
console.log(val,'setter触发');
// 中去修改依赖
this.num = val/2; // 此时doubleNum等于200
}
}
}
})
顺便延申一下关于Object.defineProperty方法
这个方法是对象的一个很重要的属性,它可以定义对象的属性值,不管这个值是否存在,原理是通过劫持对象的属性来进行获取操作和赋值操作
// Object,defineProperty(objName,[...property],{get(),set()})
let test = {
num: 0
}
let count = 1
// get和set必须成对出现
Object.defineProperty(test,'num', { // 劫持test的num属性
get: ()=>{ // 利用其他数据给计算属性返回值
return count // 此时count已经赋值给了set的newVal
},
set: (newVal)=>{ // 拦截计算属性的值
// 在setter中去修改依赖
num = newVal // 等待数据改变时触发
}
})
// 我们来测试一下结果
console.log(test.num) // 1
// 如果我们把num的值改变,看会不会影响count的值
count = 10 // get会重新返回count,将count赋值给set的newVal
console.log(test.num) // 10
5.nextTick
【此部分内容来自https://www.jianshu.com/p/a7550c0e164f】
小伙伴们都知道Vue中的DOM更新都是异步的吧
<-- 我们先确认一下DOM更新是异步操作的 -->
<div class="app">
<div ref="msgDiv">{{msg}}</div>
<div v-if="msg1">Message got outside $nextTick: {{msg1}}</div>
<div v-if="msg2">Message got inside $nextTick: {{msg2}}</div>
<div v-if="msg3">Message got outside $nextTick: {{msg3}}</div>
<button @click="changeMsg">
Change the Message
</button>
</div>
new Vue({
el: '.app',
data: {
msg: 'Hello Vue.',
msg1: '',
msg2: '',
msg3: ''
},
methods: {
changeMsg() {
this.msg = "Hello world."
this.msg1 = this.$refs.msgDiv.innerHTML
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML
})
this.msg3 = this.$refs.msgDiv.innerHTML
}
}
})
从图中可以得知:msg1和msg3显示的内容还是变换之前的,而msg2显示的内容是变换之后的。其根本原因是因为Vue中DOM更新是异步的
理解: nextTick()
是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数
使用场景
- 如果你要在
creatd()
钩子函数中进行DOM操作,就一定要放在Vue.nextTick()
的回调函数中,此时的效果就是相当于mounted()
方法,这个方法用的不错
- 如果你有个方法,需要在数据变化后就立马触发,如果你的方法涉及到DOM结构渲染,并且时随着数据的改变而改变DOM结构时,就可以考虑把这个方法写在
next Tick()
的回调函数中
// 就比如你有一个请求,这个请求到的数据关系到页面的重绘,有时候可能会存在请求数据后,数据还没到,单页面就已经渲染完成了,此时我们可以将这个请求方法放入`nextTick()`中
// `nextTick()`可以写在任意地方,比如methods,mounted...
三个重要的变量
-
callbacks
用来储存所有需要执行的回调函数
-
pending
用来标志是否正在执行回调函数
-
timerFunc
用来触发执行回调函数
给你们推荐一个贼牛皮的博客关于next Tick()
的文章