vue基础
VUE是目前前端最火的两个框架之一
是通过修改数据自动改变dom数据的框架,几乎完全的省去了dom的操作,目前vue的版本是2.x
vue有两种使用方式,一种是直接引入js,一种是使用vue-cli,也就是脚手架
不管是使用哪种,写法都是没变的,只是脚手架用在更加大型的项目,脚手架后面再说
内容全部来自vue官网
这是我第一次认真的看vue的开发文档,以前都是看视频学习的,这才发现vue还有这么多看都没看过的API
需要学会的全部内容
- 生命周期
- 指令【太多了,不写了】
- 选项/dom【ref】
- 选项/数据【data,props,computed,methods,watch,
$refs
,$nextTick
】 - 全局API的【use,set,directive,component,filter】
- 外部的【
$router
,$store
,axios】
引入
这里是一些基础的使用,所以就直接引入js做栗子
<div id="app">
{{ message }}
</div>
// 外部CDN
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
生命周期 和 ref
生命周期在大型的插件封装里是非常常见的,是表示当前运行阶段
vue的声明周期很多个,用到的有
- created:表示data数据已经加载,计算属性,watch,methods都执行好了,但是el还没挂载,第一次加载执行时用这个生命函数,我们去看vue的标签,写的时候可能是
<vue></vue>
但在页面上调试其实是个div,就是el被解析后挂载后的效果 - mounted:当前el已经挂载得差不多了,如果需要等el完全挂载,可以配合
$nextTick
使用,这个阶段是用来调用ajax - updated:当数据发生变化,就会执行这个
生命周期函数不能使用箭头函数
<div id="app">
<div ref="tt"> {{ message }} </div>
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
created(){
// 此时没有el
console.log(this.$refs) //underfined
},
mounted(){
this.$nextTick(function(){
// 这里是执行ajax的
console.log(this.$refs) //{tt:div}
})
},
updated(){
this.$nextTick(function(){
// 数据变化执行这个
})
}
})
指令
<div id="app">
<!-- 数据显示的指令
跟v-text一样但是用字符串模板{{}} 更好,还能执行方法
v-html 是很少用的,一般用在后台返回富文本数据时使用 -->
<div v-text="msg"></div>
<div v-html="html">会识别html标签</div>
<div>{{ msg + "aa" }} 可以写其他文字</div>
<!-- 逻辑判断的指令
v-if是直接看不到dom,v-show是display:none -->
<div v-show="show">显示</div>
<div v-show="!show">隐藏</div>
<div v-if="str === 'A'">A</div>
<div v-else-if="str === 'B'">B</div>
<div v-else>Not A/B</div>
<!-- 循环断的指令,可以循环数组,对象,字符串,数字
v-for要配合 :key 使用
v-for 不要跟 v-if 放在一起 -->
<div v-for="value,key,index in obj" :key="key">{{key}}:{{value}}--{{index}}</div>
<div v-for="value,index in arr" :key="value">{{value}}--{{index}}</div>
<!-- 事件绑定的指令,简写为【@】,配合methods使用,
不传参是不写括号的
事件修饰符:stop 阻止冒泡,
prevent 阻止默认事件,
self 只能亲自执行不被冒泡执行,相当于event.target,
once 只执行一次
native 使用在自定义组件上,查看《vue的自定义》笔记 -->
<input type="text" v-on:blur="myBlur($event)" />
<button @click="myClick">点击</button>
<!-- 变量绑定的指令,简写为【:】
最常用的地方是 key,组件传参,src,href,type等-->
<input v-bind:type="type" />
<a :href="href"> 可以通过 data里改href 修改 a的href </a>
<!-- 表单双向绑定的指令 -->
<input type="text" v-model="text"> <span>{{text}}</span> <br>
<input type="password" v-model="password"> <span>{{password}}</span> <br>
<input type="radio" v-model="radio" value="radio1"><input type="radio" v-model="radio" value="radio2"> <span>{{radio}}</span> <br>
<input type="checkbox" v-model="checkbox" value="checkbox1"><input type="checkbox" v-model="checkbox" value="checkbox2"> <span>{{checkbox}}</span> <br>
<select v-model="select">
<option value="select1">select1</option>
<option value="select2">select2</option>
<option value="select3">select3</option>
</select> <br>
</div>
var app = new Vue({
el: '#app',
data: {
msg: 'Hello Vue!',
html:"<input type='text'>",
show: true,
str: 'A',
obj:{
"name":"pdt",
age:18
},
arr:[10,20,30,40],
type:"password",
href: "http:www.baidu.com",
text: "text",
password:"pass",
radio:"radio2",
checkbox:["checkbox1","checkbox2"],
select:"select2",
},
methods:{
myBlur(e){ console.log(e.srcElement.value) },
myClick(){ ... }
},
})
特殊的key
指令
key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes,如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素,有相同父元素的子元素必须有独特的 key,重复的 key 会造成渲染错误
还有一个问题就是vue格式的dom标签在生命周期没进行到mounted之前是显示的,会让页面非常的难看
所以应该先隐藏,vue有个无用的指令叫v-cloak
,把这个标签写在最高级dom上,给这个属性添加隐藏功能,等到vue把el挂载这个属性就会失效,页面也正好展示出来
[v-cloak] {
display: none;
}
<div id="app" v-cloak > ... </div>
选项/dom
就是给dom元素上加上ref="xxx"
的值,相当于id,然后可以通过 this.$refs
获得一个对象,这个对象里装着所有带有 ref 属性的dom元素,这个是很少使用,只有部分插件有要求使用这个属性
选项/数据
上面的指令是数据和dom的绑定和显示,这个是vue插件替我们完成的,我们就不用再去写xx.value=="xx",xx.innerHTML="xx"了,所以只需要自己修改数据就行
我们一般使用的vue的数据写在4个地方
- data对象里
- 计算属性computed里
- prop对象里(由父组件的v-bind传过来的,这个后面单独讲)
- 还有vuex (这个后面单独讲)
<div id="app">
<div> {{ msg }} </div>
<div> {{ msg2 }} </div>
<div v-show="show">显示</div>
<div v-show="!show">隐藏</div>
<button @click="A">显示/隐藏</button>
<button @click="B">点击修改msg的值</button>
</div>
var app = new Vue({
el: '#app',
data: {
msg: 0,
show: true,
},
methods:{
// 修改data的数据只能用this.【data里的key】 = 【新value】
A(){ this.show = !show; // 取反 }
// 修改data的数据只能用this.【data里的key】 = 【新value】
B(){ this.msg = new Date().getTime(); }
},
computed:{
// 在计算属性里的值不需要写在data里,重复会冲突
// 一旦计算属性里的相关值发生变化,这个值就会重新计算
// 计算属性是需要return才能给自己赋值
msg2(){
return new Date(this.msg).getFullYear()+"-"+ (new Date(this.msg).getMonth()+1) + "-"+ new Date(this.msg).getDate() + " "+ new Date(this.msg).getHours() + ":"+ new Date(this.msg).getMinutes() + ":"+ new Date(this.msg).getSeconds()
}
}
})
vue的watch监听
这个是计算量很大的方法,vue建议能用computed尽量不用watch,但是我经常用它监听vuex的初始化数据,他是监听上面的四个数据对象的某个数据,需要四个数据对象里先有需要监听的值
注意: watch和computed不要去操作相同的数据,不然相互计算会陷入死循环
data:{
name:"xxx"
},
watch:{
name(){
console.log("值发生了改变")
}
}
watch的immediate
和deep
watch: {
// 不能写成函数了
firstName: {
handler(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
},
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
immediate: true, //默认是false
// 当watch监听的是对象,对象里的值改变是不被监听的,需要加上深度监听
deep: true //默认是false
}
}
methods是存方法的地方,$refs
在上面提到了
还有最后一个this.$nextTick
这个是配合vue的数据更新使用的,vue的数据更新后的dom更新并不是实时的,他不是你把a从1变成2他就去改一次的,他是用类似防抖的方式去控制数据变化的,他会把数据的变化攒着一口气再更新一次dom,而this.$nextTick
回调的就是下一次dom更新完要执行的东西
这个方法用得也不多,在使用轮播图插件的时候,一开始轮播图是空的,所以不会动,等图片数据从ajax请求下来后,数据更新上去但是轮播图还是不会动,就需要执行轮播图滚动的方法,如果同步执行,10次可能有5次不生效,因为你执行滚动方法的时候dom还没更新,所以解决方案有弄个定时器等大概1-2s后执行滚动方法,或者把滚动方法写在this.$nextTick
的回调里
数据添加的规定
需要用到的数据有两种,一种是一开始就声明好了的,比如现在data里先声明了name属性,那这个属性在vue的creat阶段就被监听了,但是如果是后期添加的数据,是不被监听的
<div id="app">
<div v-for="value in opt.arr" :key="value">{{value}}</div>
<div v-for="value,key in opt.obj" :key="value">{{key}}--{{value}}</div>
<button @click="A">添加数组</button>
<button @click="B">添加对象</button>
</div>
var app = new Vue({
el: '#app',
data: {
opt:{},
},
methods:{
A(){
this.opt.arr=[{name:"arr"}];
console.log(this.opt.arr)
},
B(){
this.opt.obj={name:"obj"};
console.log(this.opt.obj)
}
}
})
会发现虽然打印有数据,但是页面没数据,因为vue不知道有这个数据,js知道
想要让vue知道,需要用vue规定的添加方式
methods:{
A(){
// 在this是代表vue实例的地方这么写
this.$set(this.opt,"arr",[{name:"arr"}])
// 在this不是vue的实例的地方,比如插件的上下文里
// Vue.set(this.opt,"arr",[{name:"arr"}])
console.log(this.opt.arr)
},
B(){
// 在this是代表vue实例的地方这么写
this.$set(this.opt,"obj",{name:"arr"})
// 在this不是vue的实例的地方,比如插件的上下文里
// Vue.set(this.opt,"obj",{name:"arr"})
console.log(this.opt.obj)
}
}
数据更新的规定
当更新一个普通的数据时,直接xx="xx",vue就能反应过来,但是如果是更新数组或者对象,就有些规定了,不然就会出现数据我改了,但是没效果的BUG,具体查看vue官网的文档
vue规定修改数组用下面的方法
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
如果是
filter()、concat() 和 slice() 。它们不会改变原始数组,而总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
vm.items[1] = 'x' // 不是响应性的
// 可以改用
Vue.set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)
vm.items.length = 2 // 不是响应性的
// 可以改用
vm.items.splice(newLength)
// 清空数组
this.arr = []
vue规定修改对象用下面的方法
对象的数据需要改没有数组那么多的规定就直接赋值就行,新来的数据用set
添加
如果需要融合对象
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
可以看出,封装是有封装的局限性的,他有很多的限制,这也是为什么学习原生比学习框架更好的原因
剩下的知识点有
全局API的【use,directive,component】
外部的【$route
,$store
,axios】
剩下的这些都是在脚手架上用的多,用js引入的小项目小页面很少用
use是用于引入插件的
directive是自定义指令
component是自定义组件
filter是自定义过滤器
$route
是vue-router的路由数据
$store
是vuex的数据
axios是新的请求方式,因为省去了操作dom,就不会再引入jq了,不用jq了,jq的ajax也就不用了
除了$store
其他的几个在引入型的vue使用中都可以用的,需要用到就自行百度,查看官方文档也有,下一篇《vue-cli》