Vue基础
文章目录
Vue特点:
- 采用组件化模式,提高代码复用率,且让代码更好维护
- 声明式编码,让编码人员无需重复操作DOM,提高开发效率
- 使用虚拟化DOM+优秀的Diff算法,尽量复用DOM节点
vue基本使用:
- 想让vue工作,就必须建立一个vue实例,并且要传入配置对象
- root容器中的代码遵循HTML语法规范,但其中有特殊的vue语法
- root容器中的代码称为【vue模板】
- vue实例和容器都是一一对应的
- 真实开发中只有一个vue实例,并配合组件一起使用
- {{xxx}}中xxx为 js 表达式,且xxx可以自动读取到data中的所有数据
- 一旦vue实例中data值改变,容器中对应位置的内容也会改变
例如下方,new关键字,就创建了一个vue实例,el和data就是当前实例的配置对象,此时新创建的vue对象就可以叫做vm对象
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>hello,{{name}}</h1>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
// 创建vue实例
new Vue({
el: "#root", //el用于指定当前vue为那个容器服务
data: { //data中存储数据
name: '尚硅谷'
}
})
</script>
</body>
</html>
vue模板语法
插值语法
在root容器中将要改变插入的值写在{{}}中,并把对应的值,写在vue实例中,想改变其中内容时,直接改变vue实例中的值就好了
<div id="root">
<h1>插值语法</h1>
<h3>你好,{{name}}</h3>
<hr/>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: "#root",
data: {
name: 'qjj'
}
})
指令语法
指令一般都是v-
后面跟上相应内容,表示vue中的指令,vue实例中的相应值,就会被应用到指令这里
<div id="root">
<h1>指令语法</h1>
<a v-bind:href="url">点我去学习</a>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: "#root",
data: {
url: "http://baidu.com"
}
})
</script>
这里,v-bind:
就是一个指令,在一般应用中,可以把v-bind:简化为:
来使用,效果都只一样的
一般来说,当想把内容放置在标签体之中,一般使用插值语法,当想把内容放置在标签属性中,使用指令语法
vue数据绑定
数据绑定一共两种v-bind和v-model
,两者之间的区别:
v-bind
是单向绑定,只能通过修改vue实例中的数据,才能改变内容,直接修改页面内容,vue实例中的数据不会被修改
v-model
则是双向绑定,不论修改页面内容或者vue实例中数据,vue实例中数据都会改变,双向绑定一般应用在表单类元素上(有value值)
一般,可以把v-model:value简化为v-model
因为v-model默认就是收集的value值
el和data两种写法
el两种写法:
最常见的一种,就是将两个都写在vue实例中
new Vue({
el:"#root",
data:{
name:"123"
}
})
第二种,不在vue实例中写绑定容器,只写数据,将绑定容器放在vue实例外边,但是这个时候需要用变量接收vue实例,并使用vue中的方法v.$mount('')
在引号中写入绑定容器
const v = new Vue({
// el: "#root",
data: {
name: "尚硅谷"
}
})
v.$mount('#root')
data两种写法:
第一种,对象式,将数据作为data对象属性,写在其中
data:{
name:"123"
}
第二种,函数式,将data写作一个函数,函数必须要返回一个对象,其中有我们的数据,必须是普通函数,不能使用箭头函数
data:function(){
return{
name:"123"
}
}
//更简单一种,两种效果一样
data(){
return{
name:"123"
}
}
data函数中的this是vue,箭头函数没有自己的this,所以不提倡
数据代理(Object.defineProperty()
)
这个方法一般是用来想对象中添加属性,并且控制属性的相关操作,首先定义一个person对象:
let person = {
name: '张三',
sex: '男'
}
现在想向其中添加一个属性,年龄为18,可以直接在对象中添加,也可以使用Object.defineProperty()
其中传入三个参数(添加对象,属性名,配置对象)
这种方法添加的属性:
- 一般不能够被遍历,需要加上
enumerable:true
- 一般添加的属性的值不可以被修改, 需要加上
writable: true
- 一般不能被删除,需要加上
configurable:tru
Object.defineProperty('person', 'age', {
value: 18,
enumerable: true, //控制添加的属性可以被遍历
writable: true, //控制添加的属性值可以被修改
configurable: true //控制添加的属性可以被删除
})
但是如果这时的情况是,我们已经有了一个变量number,其中存储着年龄值,如何让添加进来的age属性等于number,并且可以随着number的改变而变化,下面是一个person对象和一个number变量
let number = 18
let person = {
name: '张三',
sex: '男'
}
可以用get函数和set函数共同来操作
get函数
当有人读取
person的age属性时,get函数(getter)就会被调用,且返回值是age的值
get(){
return number
}
set函数
当有人修改
person的age属性时,set函数(setter)就会被调用,且会收到修改的值
set(value){
number = value
}
vue中的数据代理
通过vm对象来代理data对象中属性的操作,通过数据代理,可以更加方便的操作data中的数据
基本原理:
- 通过
Object.defineProperty()
把data对象中所有属性添加到vm 上。- 为每一个添加到vm上的属性,都指定一个getter/setter。
- 在getter/setter内部去操作,(读/写)data中相应属性
vue事件处理
事件的基本使用:
- 使用
v-on:xxx
或者@xxx
绑定事件,其中xxx是事件名(例如点击,放置…) - 事件的回调需要配置在methods对象中,最终会在vm上
- methods中配置的函数,不可以用箭头函数,否则this不是vm
- methods中配置的函数,都是被vue所管理的函数,this指向vm或组件实例对象
@click="demo"
和@click="demo($event)"
效果一致,但是后者可以传参
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: '#root',
data: {
name: '尚硅谷'
},
methods: {
showInfo() {
alert('同学你好')
}
}
})
</script>
事件修饰符
vue中的事件修饰符:
- prevent:阻止默认事件
- stop:阻止事件冒泡
- once:事件只触发一次
- capture:是用事件的捕获模式
- self:只有event.target是当前操作的元素才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
例如,当容器中是一个链接时,点击它弹窗后,但不想跳转,这时候就是阻止默认事件发生,使用时间修饰符prevent,如果一个事件,想用两个修饰符,可以连着使用
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: '#root',
data: {
name: '尚硅谷'
},
methods: {
showInfo() {
alert('同学你好')
}
}
})
</script>
阻止事件冒泡
<div class="demo" @click="showInfo">
<button @click.stop="showInfo">点我提示信息</button>
</div>
键盘事件
vue中常用的案件别名:
- 回车 ==> enter
- 删除 ==> delete(捕获删除和退格键)
- 退出 ==> esc
- 空格 ==> space
- 换行 ==> tab(必须配合keydown使用)
- 上 ==> up
- 下 ==> down
- 左 ==> left
- 右 ==> right
<div id="root">
<h2>欢迎来到{{name}}</h2>
<input type="text" placeholder="按下回车提示" @keyup.enter="showInfo">
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: '#root',
data: {
name: '尚硅谷'
},
methods: {
showInfo(e) {
// if (e.keyCode !== 13) return
console.log(e.target.value);
}
}
})
</script>
系统修饰键(用法特殊):ctrl,alt,shift,meta
- 可以配合
keyup
使用,但是在使用时需要按下修饰键,同时按下其他键,然后再放开其他键,才能生效 - 配合
keydown
使用,正常触发事件
计算属性(computed)
要用的属性不存在,需要通过计算来得出
原理:底层借助了Object.defineProperty()
提供的getter和setter
get函数执行时间:
- 初次读取读取时
- 当get依赖的内容发生变化会被再次调用
计算属性最终会出现在vm上,可以直接读取调用
<div id="root">
姓:<input type="text" v-model="firstname"><br><br> 名:
<input type="text" v-model="lastname"><br><br> 全名:
<span>{{fullname}}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
const vm = new Vue({
el: '#root',
data: {
firstname: '张',
lastname: '三'
},
computed: {
fullname: {
// 当有人读取fullname的值时,就会调用get
// get调用时间:1.初次读取fullname时 2.get所依赖的内容发生变化
get() { //此处的this时vm
return this.firstname + '-' + this.lastname
},
// 当fullname被修改时,会调用set
set(value) {
const arr = value.split('-');
this.firstname = arr[0];
this.lastname = arr[1]
}
}
}
})
</script>
简写,当computed计算属性中,只使用get,不使用set时,可以简写
computed:{
fullname(){
return this.firstname + '-' + this.lastname
}
}
监视属性(watch)
监视某一个属性变化,函数立即调用,一共两种写法
第一种
写在vue实例中,当在创建vue实例时就知道监视谁
watch: {
ishot: {
//当ishot发生改变时,调用
handler(newvalue, oldvalue) {
console.log('xiugai', newvalue, oldvalue);
},
immediate: true //立即执行,初始化时,让handler直接调用
}
}
第二种
写在vue实例外,在创建过后才知道监视谁
vm.$watch('ishot', {
immediate: true,
handler(newvalue, oldvalue) {
console.log('xiugai', newvalue, oldvalue);
},
})
深度监视
vue中的watch自身默认不监视对象内部元素改变,监视多级结构中的属性变化
const vm = new Vue({
el: '#root',
data: {
ishot: true,
numbers: {
a: 1,
b: 2
}
},
watch: {
//监视多级结构中某个属性的变化
'numbers.a': {
handler() {
console.log('改变了');
}
},
//监视多级结构中所有属性的变化
numbers: {
deep: true,//深度监视
handler() {
console.log('改变了');
}
}
}
})
简写,当监视属性中,不需要深度监视,和立即执行,只需要handler函数时,可以简写
也是一共两种
第一种,写在vue实例中
watch: {
//简写
ishot(newvalue, oldvalue) {
console.log('xiugai', newvalue, oldvalue);
}
}
第二种
写在vue实例外
vm.$watch('ishot', (newvalue, oldvalue) {
console.log('xiugai', newvalue, oldvalue);
})
计算属性和监视属性对比
- computed能完成的功能,watch都能完成
- watch能完成的功能,computed不一定都能完成(watch可实现异步操作)
注意
- 所有被vue管理的函数都写成普通函数
- 所有不被vue管理的函数,最好写成箭头函数
绑定样式
一共常见的就三种,在需要情况不同时,采用不同的写法
<div id="root">
<!-- 字符串写法,当样式的类名不确定,需要动态指定时 -->
<div class="basic" :class="mood" @click="change">{{name}}</div>
<!-- 数组写法,要绑定的样式个数不确定,名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div>
<!-- 对象写法,当绑定的样式个数和名字都确定,但需要动态决定要不要时 -->
<div class="basic" :class="classObj">{{name}}</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: "#root",
data: {
name: '尚硅谷',
mood: 'normal',
classArr: ['class1', 'class2', 'class3'],
classObj: {
class1: false,
class2: false
}
},
methods: {
change() {
this.mood = "sad"
}
},
})
</script>
条件渲染
分别使用v-show和v-if
来做条件渲染,v-show
只是隐藏,但改项目还在,v-if
直接去掉该内容
<div id="root">
<!-- v-show做条件渲染 -->
<h2 v-show="false">欢迎来到{{name}}</h2>
<!-- v-if做条件渲染 -->
<h2 v-if="false">欢迎来到{{name}}</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: '#root',
data: {
name: '尚硅谷'
}
})
</script>
在使用v-if
时,v-else-if和v-else
同时也可以使用,判断的逻辑和js中一样,在使用v-else-if和v-else
之前,必须要有v-if
,且不能打断,必须要连在一起
注:使用v-if
时元素可能无法获取到
列表渲染
一个简单的列表,在vue中,使用v-for
来进行循环列表渲染,每一个标签都需要有自己的“key”
语法:v-for="(item, index) in xxx" :key="yyy"
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表</h2>
<ul>
<li v-for="(p,index) in persons" :key="p.id">{{p.name}}-{{p.age}}</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息</h2>
<ul>
<li v-for="(c,key) in car" :key="key">{{key}}-{{c}}</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //组织vue在启动时生成生产提示
new Vue({
el: '#root',
data: {
persons: [{
id: '001',
name: '张三',
age: 18
}, {
id: '002',
name: '李四',
age: 19
}, {
id: '003',
name: '王五',
age: 20
}, ],
car: {
name: '奥迪',
price: '100',
color: 'red'
}
}
})
</script>
key
key的作用:key是虚拟DOM对象的标识,当状态中的数据发生变化时, Vue会根据【新数据】生成【新的虚拟DON】
,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较 对比规则:
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
1.若虚拟DOM中内容没变,直接使用之前的真实DOM !
2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉 页面中之前的真实DOM.- 旧虚拟DOM中未找到与新虚拟DOM相同的key,创建新的真实DOM,随后渲染到到页面。
用index作为key的问题:
- 若对数据进行逆序添加,逆序删除等破坏原本排列顺序的操作时,会产生没有必要的真是DOM更新(效率低下)
- 如果结构中还包含输入类的DOM,则界面会产生问题,当进行逆序添加,逆序删除时
vue监测数据原理
vue会监视data中所有层次的数据
如何监测对象中的数据:通过setter去实现监测,且在new vue时就需要传入需要监测的数据
- 对象中后追加的属性默认不做响应式处理
- 如需给后添加的属性做响应式,需要使用
Vue.set(target,name,value)
或者this.$set(target,name,value)
如何监测数组中的数据:通过包裹数组更新元素的方法实现,本质做了两件事
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而更新页面
vue修改数组中某元素:
- API:
push(), pop(), shift(), unshift(), splice(), sort(), recerse()
- 方法:
vue.set()和vm.$set()
,不可以给vm或者vm的根数据对象添加属性 filter(), concat(), slice()
不会改变原数组,只会返回新数组
收集表单数据
类型为<input type="text"/>
,则v-model
收集的是value值,也就是用户输入
类型为<input type="radio"/>
,则v-model
收集的是value值,且要给每个标签都配置value值
类型为<input type="checkbox"/>
:
- input没有配置value属性,
v-model
收集的就是checked(true 或者 false) - input配置了value属性:
1)v-model
的初始值为非数组,则收集到的仍是(true 或者 false)
2)v-model
的初始值为数组,则收集到的就是由value组成的数组
v-model
三个修饰符:
- lazy:失去焦点再收集数据
- number:将输入的字符串中的数字,转化为number存储
- trim:省略收尾空格
内置指令:
之前见到过的:
v-bind
单向绑定解析表达式,可简写为:xxx
v-model
双向数据绑定v-for
遍历数组,对象,字符串v-on
绑定事件监听,可简写为@
v-if
条件渲染(动态控制节点是否存在)v-else
条件渲染(动态控制节点是否存在)v-show
条件渲染(动态控制节点是否展示)
学习:
v-text
:向所在节点中渲染文本内容,v-text
会直接替换掉节点中所有内容,{{xx}}插值语法不会(不支持html结构解析)v-html
用法与v-text
相同,但他支持html结构解析(但是,v-html
有安全性问题)v-cloak
没有值,本质是配合css解决网速慢时页面展示出未被渲染的内容v-once
没有值,所在节点在初次动态渲染后,就视为静态内容,以后数据的变化,不会影响该节点数据变化v-pre
跳过所在节点的编译过程,在不使用vue实例中内容的节点可以加
自定义指令
调用时间:1.指令与元素成功绑定(一开始)2.指令所在的模板被重新解析时
定义:
1.局部指令
1)
new Vue({
directives: {指令名:配置对象}
})
2)
new Vue({
directives{指令名:回调函数}
})
2.全局指令
1)
Vue.directive(指令名,配置对象)
2)
Vue.directive(指令名,回调函数)
示例:
//函数式
big(element, binging) {
element.innerText = binging.value * 10
},
//对象式
fbind: {
// 指令与元素成功绑定(一开始)
bind(element, binging) {
element.value = binging.value
},
// 指令所在元素被插入页面时
inserted(element, binging) {
element.focus()
},
// 指令所在模板被重新解析时
update(element, binging) {
element.value = binging.value
}
}
配置对象中三个回调:
bind
指令与元素成功绑定时调用inserted
指令所在元素被插入页面时调用update
指令所在模板被重新解析时调用
注:定义指令不加v-
,使用指令时要加v-
生命周期
又叫生命周期回调函数,生命回调函数,生命周期钩子,函数内部的this指向时vm或者组件实例对象
- 将要创建,调用
beforecreate
函数 - 创建完毕,调用
create
函数 - 将要挂载,调用
beforemounted
函数 - 挂载完毕,调用
mounted
函数,发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】 - 将要更新,调用
beforeupdate
函数 - 更新完毕,调用
update
函数 - 将要销毁,调用
beforedestroy
函数,清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】 - 销毁完毕,调用
destroy
函数