1 vue基础
vue
是一个MVVM
框架,Model-View-ViewModel
,是一个MVC
的前端版本
ViewModel
是一个控制器的角色,在他里面实现逻辑运算等,这样就可以把 Model
层和 View
层高度分离
View
:视图,用于封装和展示数据以及结果,其实就是html结构
Model层
:数据模型,用来封装数据已经数据运行的业务逻辑
使用vue的方法
1.通过script
引入vue
文件
2.可以通过vue-cli
创建vue
项目,进行开发
2 插值表达式
{{}}
:插值表达式,在他的里面可以执行 vue
变量,表达式,也可以执行函数
插值表达式实际上是一个js
的域,在插值表达式中可以执行简单的js语句
,并且把执行结果返回到插值表达式所在dom结构
的位置上
也可以使用指令 v-html
、v-text
绑定数据
插值表达式的缺点:初次加载的时候文本闪烁
解决方法
1.把vue文件引入到head中,不建议使用
2.使用指令 v-cloak 来隐藏数据没有加载完成的dom结构,这样可以解决页面开始的时候的闪烁问题。该指令的运行方式是,首先隐藏没有编译成功的dom结构,等到dom编译成功之后,会自动把隐藏的方式去掉
3 属性绑定
在 vue
中,{{}}
不能直接绑定属性的值
可以使用 v-bind
来绑定属性
语法是
v-bind:属性名=‘属性值/属性名’
简写方式
:属性名=‘属性值/属性名’
4 绑定style和css
- 绑定style
<div :style="'font-size:20px;color:#f00;'">多行不义必自毙</div>
- 使用 数组形式绑定class
<div :class="['abc', 'aa']">韩愈</div>
使用 对象形式绑定class,属性名为class名,属性的值是一个boolean值,如果布尔值为true,则绑定该class名,否则不绑定
<div :class="{'abc':3>4,'aa':3<4}">苏轼</div>
style和class的绑定都支持 数组形式和对象形式
5 事件绑定
v-on:事件名=“表达式/方法名”
方法名的参数问题,如果没有参数可以不加()
<button v-on:click="num++">点击++</button>
事件绑定指令的简写
@事件名=“表达式/方法名”
<button @click="()=>show('天涯何处无芳草')">点击显示</button>
6 事件修饰符
vue
提供了事件修饰符,用来提高开发效率
@事件名.修饰符.修饰符.修饰符…=触发方法
stop
阻止事件冒泡
prevent
阻止默认事件
once
只执行一次
self
当 event.target
是当前绑定元素的时候触发
capture
事件捕获的时候触发
passive
触发滚动事件的默认行为
7 按键修饰符
按键修饰符,当按下或者抬起对应修饰符的按键的时候触发
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
.exact非系统键
8 数据双向绑定
在表单元素中,使用v-model
实现数据双向绑定
双向绑定:简言之就是数据在视图层的更改会立即体现在model层,反之在model层的改变也会立即体现在视图层
- 设置单选框的
v-model
<label for="">性别</label>
<label for=""><input type="radio" name="sex" v-model="sex" value="男">男</label>
<label for=""><input type="radio" name="sex" v-model="sex" value="女">女</label>
<button @click="showSex">点击显示选择的性别</button>
- 设置复选框的
v-model
复选框中的v-model
的值是一个数组,该数组存储复选框选中的内容
<label for="">英雄</label>
<label for=""><input type="checkbox" v-model="hero" value="戚继光">戚继光</label>
<label for=""><input type="checkbox" v-model="hero" value="岳飞">岳飞</label>
<label for=""><input type="checkbox" v-model="hero" value="雷锋">雷锋</label>
<label for=""><input type="checkbox" v-model="hero" value="黄继光">黄继光</label>
<label for=""><input type="checkbox" v-model="hero" value="左宗棠">左宗棠</label>
<label for=""><input type="checkbox" v-model="hero" value="李如松">李如松</label><br>
<button @click="showHero">复选框选中的值</button>
- 修饰符
number
修饰符,把输入框中的内容转化为数字
trim
修饰符,去掉输入内容左右两边的空格
lazy
修饰符,把input事件改为change事件
9 v-if
和v-show
9.1 v-show
指令
如果他的值是true
,则他所绑定的元素显示,如果为false
,他所绑定的元素会自动添加一个display:none
,元素隐藏,v-show
改变的是css样式,属于元素重绘。
9.2 v-if
指令
如果他的值为true
,则他所绑定的元素会在dom树中对应的位置渲染,如果为false
,他所绑定的元素会从dom
树中删除,v-if
改变的是dom结构
,属于元素重排
v-else
需要结合 v-if
使用,用法同js的if-else
v-else-if
需要结合 v-if
使用,用法同js的if-else-if
10 v-for
v-for
结合 template
标签(组件) 循环数据
template 标签
不会被渲染到页面上,一般用来实现数据绑定的功能
语法:v-for=“形参 in 数组/对象”
如果需要 下标或者对象的属性名 v-for=“(形参,下标/属性名) in 数组/对象”
使用v-for
的标签元素,都需要绑定一个key属性
,属性的值一般都是要循环对象中的唯一值(例如id),使用key属性
的目的是 使已经渲染或的列表内容不在重新渲染,提高列表的渲染效率,注意index
虽然可以设置key
值,但是由于index
的值会发生变化,这样会导致列表重新渲染,因此慎用
<template v-for="item in arr" :key="item.name">
<p>{{item.name}}</p>
</template>
11 其他内置指令
v-pre
他所绑定的元素不进行vue的编译,原样输出
<p v-pre>{{str}}</p>
v-once
他所绑定的元素只渲染一次,忽略之后所以的更新
<p v-once>{{num}}</p>
v-memo
实现组件内容的缓存,如果他的值不发生改变,那么他绑定的元素不会根据数据的改变而重新渲染
<div v-memo="arr">
<h1>{{str}}</h1>
</div>
12 计算属性
如果在插值表达式中直接渲染数据,非常方便,但是如果有比较复杂的逻辑运算,{{}}
的渲染效率会受到影响,并且不利于后期维护,因此可以把比较复杂的运算逻辑放到计算属性中
每一个计算属性,实质上都包含get
和 set
两个方法,默认是get方法
在计算属性的get方法
中,不要异步请求数据(ajax)
或者操作dom
给计算属性设置值的时候,执行的是
set方法
从计算属性获取值的时候,执行的是get方法
计算属性的优点:
- 数据没有发生变化的时候,优先读取缓存在
computed
中经过逻辑运算操作的数据,把数据渲染在dom树
中,并且不用考虑methods
和watch
中数据的变化
计算属性值会基于其响应式依赖被缓存 - 有
get方法
和set方法
,可以进行灵活设置
get
在获取的时候被触发,如果没有set
,则默认是get
set
在数据设置的时候被触发
13 watch
侦听器
如果需要根据数据的变化来执行操作,可以使用数据侦听器
书写侦听器的方法,方法名就是侦听器侦听data数据
中数据的属性名,该方法具有两个参数
第一个参数是 数据当前的值(新值)
第二个参数是 数据变化之前的值(旧值)
深度监听
// 设置侦听器的深度监听
obj:{
// 设置监听的回调方法
handler(newVal,oldVal){
console.log(newVal,oldVal);
},
// 设置深度监听
deep:true,
// 设置加载立即监听
immediate:true
},
// 监听对象中某一个属性的变化
// 可以通过此方法,直接监听路由对象的变化
'obj.name'(newVal,oldVal){
console.log('监听name的变化')
console.log(newVal,oldVal);
}
14 生命周期
beforeCreate()
在组件实例初始化完成之后立即调用。此刻其他的属性和方法均没有执行或者编译created()
在组件实例处理完所有与状态相关的选项后调用。当这个钩子被调用时,以下内容已经设置完成:响应式数据(data函数
)、计算属性、方法和侦听器。然而,此时挂载阶段还未开始,因此$el 属性
仍不可用。此时不能操作dom
beforeMount()
在组件被挂载之前调用。此刻还没有挂载任何模板,因此还无法操作dom
mounted()
在组件被挂载之后调用。此时 所有的模板内容都已经被挂载,可以操作中的所有dom
常用此钩子函数来进行,加载立即执行的操作
beforeUpdate()
钩子 数据更新前触发,显示的数据是更新后的数据
但是如果改变了dom结构
,那么该函数中的dom结构
是更新前的内容update()
钩子 数据更新后触发,显示的数据是更新后的数据
如果改变了dom结构
,那么该函数中的dom结构
是更新后的内容beforeUnmount()
组件卸载之前触发unmounted()
组件卸载之后触发
13 自定义指令
directives:{
aa(el,binding){
console.log(el,binding);
el.onmouseenter=()=>{
el.style.background='#f00'
};
el.onmouseleave=()=>{
el.style.background=binding.value
};
},
}
aa
是指令名,
参数
el
表示的是自定义指令绑定的元素
binding
是一个对象,包含的属性
value
传递给指令的值
oldValue
指令绑定的数据或者元素内部发生改变的时候,改变前的值,仅在 beforeUpdate
和 updated
中有值
14 组件
14.1 组件基础
组件,将来项目开发的时候使用的都是组件,组件具有极高的复用性
注册组件
外部注册组件的关键字是component
,在实例内部注册组件,属性名为components
app.component
(组件名,组件的配置)
组件的命名
1.命名不能和原生html
冲突
2.可以使用驼峰,使用驼峰的时候,在视图模板中书写驼峰的大写字母变为-
,例如abCd,使用的时候写为<ab-cd />
3.推荐使用w3c
的命名规则:aa-bb
14.2 组件的属性
给组件设置属性,属性名设置在一个数组中,简写props:['abc','aa','obj']
,
components:{
show:{
template:'#show',
// 设置属性的具体类型,设置属性的多样性
props:{
abc:{
// 设置属性abc的值必须是一个字符串
type:String,
},
aa:{
type:String,
// 设置为必写属性
required:true,
// 设置属性的默认值,当属性没有值的时候,默认显示的内容
default:'中午吃啥'
},
obj:{
type:Object,
// 设置一个默认值,对象类型的默认值是一个函数,返回一个默认对象
default(){
return {
name:'燕青',
abc:20
}
}
}
}
}
}
14.3 refs
组件中,通过this.refs
获取所有携带 ref属性
的组件实例,this.$refs
是一个集合
this.$refs.aa
就可以获取 ref="aa"
的 组件实例
<div id="app">
<show ref="son"></show>
<button @click="change">点击++</button>
<div class="wp" ref="wp"></div>
</div>
let show={
data(){
return{
num:1
}
},
template:'#show',
methods: {
add(){
this.num++;
}
},
}
createApp({
data(){
return{}
},
components:{
show:show
},
methods:{
change(){
// 获取组件实例
console.log(this.$refs);
// 执行组件实例中的方法
this.$refs.son.add();
this.$refs.wp.innerHTML=this.$refs.son.num;
}
}
}).mount('#app')
14.4 子组件向父组件传值
使用 $emit()
触发自定义事件,并且可以传递参数
子组件中的操作
this.$emit('event-name',args参数);
然后把 event-name
绑定到子组件上
<son @event-name="父组件的接收方法"></son>
过程:
子组件中 执行this.$emit()
,触发了 绑定在子组件上的event-name
,然后执行父组件的接收方法,父组件的接收方法接收一个默认的参数,参数的值是 子组件中this.$emit
传递的参数,这样通过参数的形式,把数据从子组件传递到父组件
$parent
获取当前组件的父组件,如果没有父组件则返回null
$root
获取当前组件的根组件,如果当前组件没有父组件,则返回当前组件
<div id="app">
<h1>{{info}}</h1>
<son @abc="changeInfo"></son>
<button>点击++</button>
</div>
<template id="son">
<div class="wp">
<h1>{{msg}}</h1>
<button @click="pass">点击传递给父组件</button>
<button @click="getFu"></button>
</div>
</template>
let son={
data(){
return{
msg:'到不轻传'
}
},
template:'#son',
methods: {
pass(){
this.$emit('abc',this.msg);//触发事件
},
getFu(){
this.$parent.changeInfo(this.msg);
this.$root.changeInfo(this.msg);
}
},
}
createApp({
data(){
return{
info:'稻香'
}
},
components:{
son
},
methods:{
changeInfo(data){
console.log('触发方法',data);
this.info=data;
}
}
}).mount('#app');
14.5 父子组件传值
<div id="app">
<h2>{{msg}}</h2>
<hr>
<abc :info="msg" @pass="getData"></abc>
</div>
<template id="abc">
<h1>{{info}}</h1>
<button @click="change">点击传递给父组件</button>
</template>
let abc={
template:'#abc',
props:['info'],//设置属性
data(){
return{
str:'夕阳无限好'
}
},
methods: {
change(){
// 触发pass事件,传递str数据
this.$emit('pass',this.str)
}
},
}
createApp({
data(){
return {
msg:'我看青山如是'
}
},
methods:{
// data默认参数,是子组件通过$emit传递过来的数据
getData(data){
this.msg=data
}
},
components:{//设置内部组件
abc
}
}).mount('#app');
14.6 非父子关系组件传值
<div id="app">
<h1>摇滚不死</h1>
<son1></son1>
<son2></son2>
</div>
<template id="son1">
<div class="son1">
<h2>子组件1</h2>
<h4>{{msg}}</h4>
<button @click="pass">点击传递给子组件2</button>
</div>
</template>
<template id="son2">
<div class="son2">
<h2>子组件2</h2>
<h4>{{info}}</h4>
</div>
</template>
//引入mitt实例
let bus=mitt();
// 声明两个组件
let son1={
template:'#son1',
data(){
return{
msg:'假行僧'
}
},
methods: {
pass(){
// 执行mitt 实例中的 emit() 方法,来触发自定义事件 并且 传递数据
bus.$emit('abc',this.msg);
}
},
};
let son2={
template:'#son2',
data(){
return{
info:'一款红布'
}
},
mounted(){
// 执行mitt 实例中的 on() 方法,来监听 自定义事件是否被触发,如果被触发,则执行回调函数,回调函数默认传入一个参数,该参数的值即为通过 emit 触发事件传递的数据
bus.$on('abc',data=>{
this.info=data;
})
}
};
createApp({
data(){
return{}
},
components:{
son1:son1,
son2:son2
}
}).mount('#app');
14.7 provide和inject传值
<div id="app">
<h1>{{str}}</h1>
<zi></zi>
</div>
<template id="zi">
<div class="wp">
<h1>子组件</h1>
<sun></sun>
</div>
</template>
<template id="sun">
<div class="wp">
<h1>孙组件</h1>
<p>{{msg}}</p>
</div>
</template>
let sun={
template:'#sun',
// 通过inject 直接接收 provide 传递的数据
inject:['msg']
}
let zi={
template:'#zi',
components:{
sun
}
}
createApp({
data(){
return{
str:'却热三千烦恼丝'
}
},
// 配置直接传入后代的值
// provide:{
// mag:'却热三千烦恼丝'
// },
// 如果直接获取data 中的数据作为传递到后代组件的数据,则使用函数的形式返回数据
provide(){
return{
msg:this.str
}
},
components:{
zi
}
}).mount('#app')
14.8 动态组件
使用标签 component
该组件具有一个 is 属性
,is属性
的值 是 要渲染组件的名字,即为is属性
的值是哪一个组件名,component 标签
就会渲染哪一个组件
缺点:
component
可以动态渲染组件的内容,但是每一次切换,都会重新渲染组件内容,降低渲染效率
使用 keep-alive 标签
(组件),可以缓存曾经渲染过的组件,从而提高渲染效率
<keep-alive>
<component :is="'comp'+num"></component>
</keet-alive>
15 插槽
插槽 指的是 写入自定义组件中包裹的内容,一般都是 html结构
或者自定义组件
插槽的出口,在自定义组件内部,设置一个slot 标签
,表示插槽的出口,将来插槽的内容会渲染在slot 标签
所在的位置
如果需要 不同的插槽内容渲染在 组件中不同的位置,那么需要使用具名插槽
具名插槽的名字设置方式:
1.在插槽的内容部分,设置 `v-slot:插槽`名 来包裹需要渲染在具体位置的html内容结构
2.在自定义组件中,设置 `slot`在对应的位置,并且 `slot`的 `name属性值`是 插槽名
注意: v-slot:插槽名 可以简写成 #插槽名
使用 指令 v-slot
绑定的插槽名字可以是一个变量
v-slot:[变量名]
#[变量名]
<div id="app">
<son2>
<template v-slot:header>
<h3>一人得道鸡犬升天</h3>
</template>
<p>我爱郑科</p>
<p>鸡你太美</p>
<p>鸡你太美</p>
<p>鸡你太美</p>
<template #footer>
<h3>风吹草低见牛羊</h3>
</template>
</son2>
</div>
<template id="son2">
<slot name="header"></slot>
<h1>方便面</h1>
<slot></slot>
<slot name="footer"></slot>
</template>
16 过渡动画
设置过渡的流程
1.把需要使用过渡动画的元素使用transition
组件包裹起来
2.给transition
组件设置一个name
属性
3.通过name
属性的值,设置过渡动画
4.控制元素或者组件的显示和隐藏
Transition-group
组件,常用来操作一系列数据,它具有一个tag属性
,可以把当前的Transition-group
组件 渲染为tag属性
设置的html标签
过渡动画的应用场景
- 结合v-if使用
- 结合v-show使用
- 结合 路由切换使用
17 简单路由
vue-router 中,使用 router-link 来设置路由的导航,通过他的to属性来配置路由的地址,每一个router-link组件最后会被渲染成一个a标签
router-view 组件,通过 router-view 组件来设置路由的出口,路由匹配到地址栏中的地址,会把和该地址对应的 组件内容 渲染到 router-view 组件中来