一、vue介绍
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
什么是渐进式框架?
渐进式:一步一步,不是说你必须一次把所有的东西都用上
自底向上设计:是一种设计程序的过程和方法,就是先编写出基础程序段,然后再逐步扩大规
模、补充和升级某些功能,实际上是一种自底向上构造程序的过程。
最核心的是视图层渲染,然后往外是组件机制,在此基础上再加入路由机制,再加入状态管理,最外层是构建工具,vue和react都是如此。
优点
- 组件化开发
- 单页面路由
- 丰富的Api方法
- 双向的数据绑定
- 单向数据流
- 易于结合其他第三库
- 最适合于构建视图项目,移动端项目
缺点
- 生态系统不够完善
- 可扩展性稍差
SPA(单页面应用)介绍
多页面应用有多个html文件,通过a标签的连接联通各个页面
- 缺点
- 开发起来太冗余,编译、压缩很耗时间
- 页面之间的跳转速度太慢,这个时候就会出现一个严重的问题,白屏
单页面应用(SPA)
- 不需要刷新页面,因为它就是一个页面
- 这个页面内容在切换
- 单页面内容之间的切换要想实现我们就是用路由了
- 如今我们的app、后台管理系统 ,可视化主要的开发形式就是spa
二、vue基本使用
引入vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue引入</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Vue的生命周期'
}
})
</script>
插值与指令
- 插值表达式:是vue框架提供的一种在HTML模板中绑定数据的方式,使用 {{变量名}} 方式绑定Vue
实例中data中的数据变量,会将绑定的数据实时的在视图中显示出来。 - 什么是指令?
指令的本质就是标签中的vue自定义属性
指令格式以“v-”开始,例如:v-text、v-html等
指令有什么作用?
当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM。(简化操作)
小试牛刀:v-text指令与v-html指令【相当于innertHTML和innerText】
友情提醒:v-html尽量少用甚至不用,因为可能引发XSS攻击。
data属性
Vue中的data属性专门用来以对象方式存放数据,在组件中,只接受data(){return {a:1,b:2,}},
,即将data作为一个函数名、数据对象作为函数返回值来使用。因为组件可能被用来创建多个实例。如果data仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供data函数,每次创建一个新实例后,我们能够调用data函数,从而返回初始数据的一个全新副本数据对象。
注意:data响应数据,发生改变,页面自动更新同步。
computed计算属性
在模板中可以把computed当作data属性来使用,computed是一个对象,每个键是计算属性的值,值有两种使用方法:值是一个函数,或者值是一个包含get和set的对象
注意:computed有缓存,data不变则不会重新计算
<template>
<div>
num: {{num}} <br>
doubule1:{{doubule1}} <br>
<input type="text" v-model="doubule2">
</div>
</template>
<script>
//this指当前vue实例
//computed 1.就当数据使用 2.缓存 3.依赖data而变化
export default {
data(){
return{
num:2
}
},
computed:{
doubule1(){ //4
return this.num * 2
},
doubule2:{ //6
get(){
return this.num * 3
},
set(val){
console.log(val)
this.num = val
}
}
}
}
</script>
条件渲染
v-if
指令用于条件性地渲染一块内容,也可以用 v-else
添加一个“else 块”.v-else-if
,顾名思义,充当 v-if
的“else-if 块”
面试题:v-if中的key作用?
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。但是如果你就是要某个元素不复用也行,加个 key
<div v-if="login === '10086'">
<label>10086</label>
<input placeholder="Enter 10086" key="10086-key">
</div>
<div v-else>
<label>10088</label>
<input placeholder="Enter10088" key="10088-key">
</div>
在这种情况下用户的输入每次都会被重置,默认情况没有刷新的ui是会被复用的,诸如用户输入内容是会被保留的
面试题:v-show使用场景?
v-if和v-show都是用来控制元素的渲染。v-if判断是否加载,可以减轻服务器的压力,在需要时加载,但有更高的切换开销;v-show调整DOM元素的CSS的dispaly属性,可以使客户端操作更加流畅,但有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
<template>
<div>
<h1>v-if使用</h1>
<p v-if="num == 1">1</p>
<p v-else-if="num == 2">2</p>
<p v-else>3</p>
<h1>v-show使用</h1>
<p v-show="num == 1">1</p>
<p v-show="num == 2">2</p>
</div>
</template>
<script>
export default {
data(){
return{
num:2
}
}
}
</script>
循环
我们可以用 v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名。
你也可以用 v-for
来遍历一个对象的 property。例如 v-for="(value, name, index) in object"
注意:key的重要性,key不能乱写(如random或index),v-for和v-if不能一块使用,同一行
<template>
<div>
<h1>遍历数组</h1>
<ul>
<li v-for="(item,index) in arr" :key="item.id">
{{index}} --- {{item.name}}
</li>
</ul>
<h1>遍历对象</h1>
<ul>
<li v-for="(val,key,index) in obj" :key="key">
{{index}}---{{key}}---{{val}}
</li>
</ul>
</div>
</template>
<script>
export default {
data(){
return{
arr:[
{id:1,name:'a'},
{id:2,name:'b'},
{id:3,name:'c'},
{id:4,name:'d'},
],
obj:{
name:'张三',
age:22,
sex:'男'
}
}
}
}
</script>
事件
可以用 v-on
指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
1. 绑定监听:
v-on:xxx="fun"
@xxx="fun"
@xxx="fun(参数)"
默认事件形参: event
隐含属性对象: $event
2. 事件修饰符:
.prevent : 阻止事件的默认行为event.preventDefault()
.stop : 停止事件冒泡 event.stopPropagation()
3. 按键修饰符
.keycode : 操作的是某个keycode值的健
注意按键修饰符是按键名的只有少数特殊按键可以这么简写
.enter : 操作的是enter键
注意:事件对象event是原生的,对比react不是.事件被挂载到当前元素和 DOM 事件一样
<template>
<div>
<h1>事件</h1>
<ul>
<li v-for="(item,index) in arr" :key="index">
ID:{{item.id}}----姓名:{{item.name}}
</li>
</ul>
<button @click="addFun">添加</button>
<div id="parent" @click="par()">
<div id="son" @click="son()"></div>
</div>
<a href="http://www.baidu.com" @click="dianji()">跳转</a>
<!-- 当我输入回车的时候才会触犯sr事件 -->
<input type="text" @keyup.enter="shuru($event)" />
</div>
</template>
<script>
export default {
data(){ //响应数据
return{
arr:[
{id:1,name:'张三'},
{id:2,name:'李四'},
]
}
},
methods:{
addFun(event){ //添加函数
console.log(event)
this.arr.push({
id:`${Date.now()}`,
name:'王五'
})
},
par(){
alert("我是父亲");
},
son(){
alert("我是儿子");
/* 阻止事件冒泡 */
event.stopPropagation();
},
dianji(){
alert("不能跳转");
/* 阻止事件默认行为 */
event.preventDefault();
},
shuru(e){
if(e.keyCode=13){
alert("我要提交");
}
}
}
}
</script>
表单
v-model
提示表单有:input textarea checkbox radio select
作用:表单元素的绑定,实现了双向数据绑定,通过表单项可以更改数据。
v-model会忽略所有表单元素的value、checked、selected特性的初始值,而总是将Vue实例的数据
作为数据来源,在data选项中声明初始值
修饰符 lazy
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
number
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符:
<input v-model.number="age" type="number">
trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符:
<input v-model.trim="msg">
组件
组件间通讯1-props(类型和默认值)和$emit(父子)
组件间通讯2-自定义事件总线(非父子组件通信)
组件声明周期(理解)
每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂
载实例到 DOM,在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,目的是给予用户在一些特定的场景下添加他们自己代码的机会。
单个组件生命周期
单组件声明周期图
挂载: beforeCreate => created => beforeMount => mounted
更新: beforeUpdate => updated
销毁: beforeDestroy => destroyed
beforeCreate
在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
created
实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount
在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted
el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
beforeUpdate
数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。
该钩子在服务器端渲染期间不被调用。
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
created和mounted有什么区别?
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
父子组件生命周期
index组件-input组件-list组件
父子组件生命周期图
挂载: parent beforeCreate => parent created => parent beforeMount => child beforeCreate => child created => child beforeMount => child mounted => parent mounted
更新: parent beforeUpdate => child beforeUpdate => child updated => parent updated
销毁: parent beforeDestroy => child beforeDestroy => child destroyed => parent destroyed
从以上能够看出:
挂载时,子组件是在父组件before mount后开始挂载,并且子组件先mounted,父组件随后
更新时,子组件是在父组件before update后开始更新,子组件先于父组件更新
销毁时,子组件是在父组件before destroy后开始销毁,并且是子组件先销毁,父组件随后。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DNYVIszG-1685269742824)(D:\2021-08-30\讲义\02vue\img\1630392421947.png)]
作业:整理一个单组件声明周期,和父子组件生命周期的执行顺序图。
三、高级特性(进阶)
filter过滤
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
场景:日期格式化 大小转换 正则过滤
<template>
<div>
{{message | lower}}
</div>
</template>
<script>
export default {
filters: {
lower(value) {
return value.repalce('/a/','a')//toLowerCase()
}
},
data() {
return {
message: 'Hello Vue'
}
}
}
// 全局过滤器,过滤价格
Vue.filter('filterMoney', (val) => {
return "¥ " + Number(val).toFixed(2) + " 元";
})
watch监听【重要】
注意:
watch监听对象需要深度监听,默认是浅监听
watch监听引用类型,拿不到oldValue
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xKQMUlIG-1685269742824)(img\1625019529944.png)]
自定义指令
除了核心功能默认内置的指令,Vue也允许注册自定义指令。有的情况下,对普通 DOM 元素进行
底层操作,这时候就会用到自定义指令绑定到元素上执行相关操作。
自定义指令分为: 全局 指令和 局部 指令,当全局指令和局部指令同名时以局部指令为准。
自定义指令常用钩子函数有:
bind:在指令第一次绑定到元素时调用
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
update:数据更新时调用
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
请注意:不管在定义全局还是局部自定义指令时,所提及的指令名均是不带 v- 前缀的名称。
语法如下:
// 全局
Vue.directive('指令名', function (el,binding) {
// 业务逻辑
})
// 局部
directives: {
指令名: function (el,binding) {
// 业务逻辑
}
}
案例如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z2EiIo9a-1685269742825)(img\1625020604977.png)]
自定义v-model【注意双向绑定实现原理】
场景:实现一个自定义v-mode的形式 用在组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Uj0pLSZ-1685269742825)(img\1603104634638.png)]
$nextTick(重要)
mounted挂载后
场景:vue是异步渲染的框架,react也是,data改变之后,dom不会立刻渲染,$nextTick会在dom渲染之后被触发,作用:以获取最新dom节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3D98qGv-1685269742826)(img\1617935784026.png)]
refs【组件通信3】
场景:vue处理不了的,使用dom元素来出处理,获取子元素或子组件的值和方法
ref 链:父组件要给子组件传值,在子组件上定义一个 ref 属性,这样通过父组件的 r e f s 属性就可以获取子组件的值了,也可以进行父子,兄弟之间的传值 ( refs 属性就可以获取子组件的值了,也可以进行父子,兄弟之间的传值( refs属性就可以获取子组件的值了,也可以进行父子,兄弟之间的传值(parent / $children与 ref类似)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ew4mGTON-1685269742826)(img\1603104746684.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sJHTZltf-1685269742827)(img\1603782273813.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRrPFM6Q-1685269742828)(img\1603782296596.png)]
provide和inject【组件通信4】
场景:更改全局背景色,全局字体,全局样式,全局风格,中英文切换等等
注意:boolean,number,string这种,他就不会动态变化,而如果是object,则能够视图响应数据变化
只要组件有继承关系就能使用
把当前父组件打包成一个组件对象
provide() {
return {
elTest: this //组件独享 方法 属性
}
}
所有子组件调用包括多个层级,爷爷-儿子-孙子
inject: ['elTest']
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d4o5aVG0-1685269742828)(img\1625039202555.png)]
slot(重要)插槽
匿名插槽基本使用
在子组件内使用特殊的元素就可以为这个子组件添加一个 slot (插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的标签及它的内容
场景:父组件和子组件插入一些东西,包括组件,dom节点,任何东西
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yhgANjQ5-1685269742829)(img\1617949017208.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywQIfq0l-1685269742829)(img\1617949033043.png)]
作用域插槽
说白了就是我在组件上的属性,可以在组件元素内使用!
场景:组件拿到插槽里面的对象,数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TY72XTWB-1685269742830)(img\1603105142046.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dBQT40Bz-1685269742831)(img\1603105159642.png)]
具名插槽
具名插槽,就是给这个插槽起个名字,在组件中,我给插槽起个名字,一个名字叫"girl",一个名字叫"boy",还有一个不起名字。
然后再内,slot属性对应的内容都会和组件中name一一对应。
场景:多个插槽的场景
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gR2aL1u3-1685269742832)(img\1602241675547.png)]
动态组件
vue内置的组件:
多个组件通过同一个挂载点进行组件的切换,is的值是哪个组件的名称,那么页面就会显示哪个组件。
用法:
渲染一个“元组件”为动态组件。依 is
的值,来决定哪个组件被渲染
场景:需要根据数据,动态渲染的场景,组件类型不确定
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kL2buJIt-1685269742832)(img\1603106229766.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-myAVtH8E-1685269742833)(img\1625103748667.png)]
transition动画
用法:
<transition>
元素作为单个元素/组件的过渡效果。<transition>
只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中。
在进入/离开的过渡中,会有 6 个 class 切换。
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。v-leave
:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移除。
<button @click="startTrans">开始动画</button>
<transition name="slide"
@after-enter="afterEnter"
@leave="afterLeave">
<p v-if="show" class="anima">动画</p>
<!-- <p class="anima">动画1</p> -->
</transition>
。。。。。。。。。。。。
methods:{
startTrans(){
this.show = !this.show
},
afterEnter(e){
e.style.left = '400px'
},
afterLeave(e){
e.style.left = '0px'
}
}
进场和离场动画
.anima{
height: 50px;
width: 50px;
background-color: red;
position:absolute;
}
.slide-enter,.slide-leave-to{
left:0px
}
.slide-enter-active,.slide-leave-active{
transition:all 2s linear;
}
.slide-enter-to,.slide-leave{
left:400px;
}
动画常用第二种方案:
1.安装 animate.css 包
2.import animated from 'animate.css' Vue.use(animated)
3.使用
我们可以通过以下 attribute 来自定义过渡类名:
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
<!-- 控制数据的值切换显示隐藏 -->
<button @click="show=!show">transition</button>
<!-- <transition enter-active-class="animated zoomInLeft" leave-active-class="animated zoomOutRight">
<p v-show="show"></p>
</transition> -->
<!-- 多元素运动 -->
<transition-group enter-active-class="animated zoomInLeft" leave-active-class="animated zoomOutRight">
<p v-show="show" :key="1"></p>
<p v-show="show" :key="2"></p>
</transition-group>
注意:如果完成前三部还是没有效果,可能就是animate.css版本的问题了
直接安装的都是最新版本,而vue官网引入的是3.5.1版本
异步组件
场景:import函数,按需加载,异步加载大组件,vue常用性能优化方案之一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuPdHe9s-1685269742834)(img\1625104284235.png)]
keep-alive 等价于v-show
场景:缓存组件,频繁切换,不需要重复渲染的情况,vue常用性能优化方案之一
用法:
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
当组件在 <keep-alive>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
属性:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存。max
- 数字。最多可以缓存多少组件实例。
复杂的组件使用keepalive 简单的可以使用v-show来提高性能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WrFau9mq-1685269742834)(img\1625106492239.png)]
mixin[不推荐使用 了解]
作用:多个组件有相同的逻辑,抽离出来,使用mixin,但是mixin并不是完美的解决方案,暂时能用,vue3提出的composition api旨在解决这些问题(
问题如下:
1.变量来源不明确,不利于阅读
2.多个mixin可能造成冲突,
3.mixin可能出现多对多关系,关系会复杂
场景:多组件调用相同的逻辑时使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEBOamvm-1685269742835)(img\1625107735041.png)]
全局注册组件或插件
组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue。
简单来说:头部组件,nav组件,swiper组件,image组件,footer组件,loyout组件,asider组件等
插件 (Plugin) 是用来增强你的技术栈的功能模块,一般是方法,它的目标是 Vue 本身。
简单来说,插件就是指对Vue的功能的增强或补充。一般都是js文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-91yJbDME-1685269742835)(img\1625119244065.png)]
四、vuex【组件通信5】
vuex介绍
- **VueX 是一个专门为 Vue.js 应用设计的状态管理架构,统一管理和维护各个vue组件的可变化状态(你能够理解成 vue 组件里的某些 data )。**大白话:集中管理数据的模块
- 它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex有五个核心概念,state, getters, mutations, actions, modules。
- 状态管理: 简单理解就是统一管理和维护各个vue组件的可变化状态(你能够理解成vue组件里的某些data)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XMgFxvVM-1685269742836)(img\1602244775741.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dCo6eixb-1685269742837)(img\5e2d871cdccd43db989cd9b826895674-1.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ATW2c5U-1685269742837)(img\eabfc484f563410c9a0edc471da66f22-1.jpg)]
vuex在vue中如何使用
state
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oD2s2XO8-1685269742838)(img\1625212389736.png)]
getters
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjVVZX0L-1685269742839)(img\1625212416865.png)]
mutations
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5dsUHY89-1685269742840)(img\1625191448450.png)]
actions
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PbryjUG-1685269742840)(img\1625193338262.png)]
mapState
computed: {
/**
* 数组形式
* 当映射的计算属性的名称与 与模块中vuexTest中state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组,
* */
…mapState(“vuexTest”, [“moduleVal”, “moduleName”]),
// “vuexTest” 指向模块vuexTest,"moduleVal"表示store.vuexTest.moduleVal
调用函数
1.state 默认局部空间 在模块中,state 是被限制到模块的命名空间下,需要命名空间才能访问。
getters,actions,mutations 默认是全局空间。actions 和mutations, 其实还有 getters 却没有被限制,在默认情况下,它们是注册到全局命名空间下的,所谓的注册到全局命名空间下,其实就是我们访问它们的方式和原来没有module 的时候是一样的
如何限定命名空间?
namespaced:true,//actions, mutations, getters, 也可以限定在当前模块的命名空间中,就不是全局的了
开启限定空间代码如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5ChAiHI-1685269742841)(img\1625207444583.png)]
开启状态下如何调用?代码如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UXU7sEPw-1685269742842)(img\1625208716610.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDkQsUQw-1685269742842)(img\1625209376069.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2COMh5bk-1685269742843)(img\1625210798453.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aObMN9CS-1685269742844)(img\1625211538428.png)]
五、vue-router使用
路由模式(hash, h5 history)
hash模式(默认) 例如:http://abc.com/#/user/10
h5 history模式 例如:http://abc.com/user/20 需要server端支持
注意:history有如下问题,vue2.0缺陷
大白话:hash路由自带404错误页面,但是history必须手动加一个404页面。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiQxfhGj-1685269742845)(img\1602245274479.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qBDNlC26-1685269742846)(img\1625536651059.png)]
路由配置
常用配置
import Home from '../../Home.vue'
const routes = [
{
path: '/',
redirect: '/home' //重定向
},
{
path: '/home',
name:'home',
component: Home
}]
如果你使用的是 hash , 那么a标签就可以了、
如果你使用 history , 那么我们最好将a标签改成 router-link 这个组件
router-link 这个组件 身上必须要有一个 to 属性
router-link 这个组件身上加一个 keep-alive属性可以进行浏览器缓存
二级路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QiHanNOE-1685269742846)(img\1625539623079.png)]
//作业:定义一个home页面,有头部组件,左侧菜单组件,内容部分嵌套
二级路由,有商品内容页,用户管理页
路由传参
传参
<router-link :to = "{name: 'list',params: {id: xxx}, query: {xxx:xxx}}"></router-link>
params传参 是在实体中传参 其实就post传参
query 传参 是在url传参 其实就get传参
接收参数
this.$route.params.id
this.$route.query.xxx
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-26Yjn2H7-1685269742847)(img\1625550618905.png)]
编程式导航
push
this.$router.push('/home')
this.$router.push({name,params,query})
push可以将我们的操作存放到浏览器的历史记录,可以回退,可以前进
replace
this.$router.replace(’/home’)
this.$router.replace({name,params,query})
replace没有将我们的操作存放到浏览器的历史记录, 效果为返回了二级
push/replace的参数就是to属性的参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vmdRknJm-1685269742848)(img\1625551865551.png)]
路由进阶 – 导航守卫
思考: 有一个业务,当我们点击 /mine的时候,要自动跳转到 /mine/login,这个时候我们发现手段不够用了,生命周期钩子函数也实现不了,这个我们想,如果我们能监听到路由的变化,那该有多好?
解决; vue为了能够监听路由的变化情况,给了一个解决方法: 这个就是导航守卫,导航钩子
导航守卫分为:全局的、单个路由独享的、组件内的三种。
【全局的】:是指路由实例上直接操作的钩子函数,他的特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数,如下的写法。钩子函数按执行顺序包括beforeEach、beforeResolve(2.5+)、afterEach三个。
router.beforeEach((to, from, next) => {
//在路由跳转前触发,参数包括to,from,next(参数会单独介绍)三个,//这个钩子作用主要是用于登录验证,也就是路由还没跳转提前告知,以免//跳转了再通知就为时已晚。
})
router.beforeResolve((to, from, next) => {
//这个钩子和beforeEach类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。即在 beforeEach 和 组件内beforeRouteEnter 之后,afterEach之前调用。
})
router.afterEach((to, from) => {
//和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next,他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫,后讲)之前。
})
【路由独享的】是指在单个路由配置的时候也可以设置的钩子函数,其位置就是下面示例中的位置,也就是像Foo这样的组件都存在这样的钩子函数。目前他只有一个钩子函数beforeEnter
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
【组件内的】:是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。钩子函数按执行顺序包括beforeRouteEnter、beforeRouteUpdate (2.2+)、beforeRouteLeave三个。
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
动态路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffsOo2PD-1685269742848)(img\1625557065092.png)]
懒加载路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j2R5Gesx-1685269742849)(img\1602245496735.png)]
六、vue原理(大厂必考1\3)
组件化
谈谈你对组件化的了解?(重点)
组件 (Component)是 Vue.js 最强大的功能之一,组件是一个自定义元素或称为一个模块,包括
所需的模板(HTML)、逻辑(JavaScript)和样式(CSS)。
组件化开发的特点:
标准
分治
重用
组合
组件也是有 全局(component) 与 局部(components) 之分。
组件名称命名方式
短横线方式(推荐)
my-component
大驼峰方式(只能在其他组件模板字符串中使用,不能在HTML模板中直接使用)
MyComponent
大驼峰式组件名不能在HTML模板中直接使用,如果需要在HTML模板中使用,需要将其进行
特定规则转化:
首字母从大写转为小写
后续每遇到大写字母都要转化成小写并且在转化后的小写字母前加 -
例如, WoDeZuJian 这个大驼峰组件名在HTML中使用的时候需要写成 wo-de-zu-jian
对比vue和react组件化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qD2cgs1e-1685269742849)(img\1602246370118.png)]
和传统组件相比,传统组件只是静态渲染,更新还要依赖于操作dom,而当今流行的框架,vue通过mvvm实现数据驱动视图,react通过setState实现数据驱动视图,而什么叫数据驱动视图,就是我们不在操作dom,我们直接改数据就可以了,使我们更加关注数据,更加关注业务逻辑。
说下什么是mvvm?(重点)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWONvvvD-1685269742850)(img\1602246765612.png)]
m->model,v->view,vm->viewModel。dom通过监听事件操作vue里的data,反之vue中的data通过指令操作dom,这就是所说数据驱动视图,这就是mvvm的理解。
- 优点
低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
双向数据绑定的原理
当把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,使用Object.defineProperty把这些属性全部转为getter/setter(数据劫持/数据映射)。在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-td1RD997-1685269742850)(D:\2021-08-30\讲义\02vue\img\1630915562045.png)]
由于vue底层是用Object.definepropty 实现的数据劫持,注意:有一个bug是,vue不能监听到对象数据的添加和删除
响应式
组件data数据一旦变化,立刻触发视图的更新是怎么实现的?(重点)
vue2.0核心api是Object.defineProperty,vue3.0是启用provy实现响应式监听
数组监听都是重写array里面的push.pop.unshift…
Object.defineProperty存在一些问题(深度监听需要一次性递归,无法监听新增属性和删除属性,无法原生监听数组,需要特殊处理),provy兼容性不好,低版本和ie11不能用
vdom和diff
为什么要虚拟DOM?
当用传统的api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。比如当你在一次操作时,需要更新10个DOM节点,理想状态是一次性构建完成DOM树,再执行后续操作。但是浏览器没有那么智能,在收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程,显然前面几次都是白白浪费性能。而且操作DOM的代价是很昂贵的,频繁操作可能会出现页面卡顿,影响用户的体验。
虚拟DOM就是为了解决这个浏览器性能问题而被设计出来的,如果一次操作中有10次更新DOM的操作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存在本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,通知浏览器去执行绘制工作,这样可以避免大量的无谓的计算量。
优点:
-虚拟DOM具有批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染,优化性能.
缺点:
-首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
vue 首屏时间长,白屏问题。
dom和虚拟dom对比
如何将虚拟dom转为真实dom基本操作?
//dom
<ul id='test' class="header">
<p class='hehe'>这里是p标签</p>
</ul>
//对应的虚拟dom对象
let vdom={
tag:'ul',
attr:{
id:'test',
class:'header'
},
content:[
{
tag:'p',
attr:{
class:'hehe'
},
content:'这里是p标签'
}
]
}
作业:手写一个虚拟dom?[笔试题]
diff算法如何进行比较的?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SztFVTdC-1685269742851)(img\1625646945801.png)]
diff->只比较同一层级,不跨级比较,tag不相同直接删掉重建不在深度比较,tag和值两者都相同,则认为是相同节点,不在深度比较
模板编译
vue模板是什么东西?
vue模板,他不是html,有指令,插值,js表达式,能实现判断,循环,html是标签语言,只有js才能实现判断,循环,vue他通过vue template complier将模板编译为render函数,执行render函数生成vnode,在渲染和更新。(react一直用render函数,没有模板)
异步渲染
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ITvo50vQ-1685269742851)(img\1625646846578.png)]
上面这一段代码中,在mounted里给val属性进行了两次赋值,如果页面渲染与数据的变化完全同步的话,页面应该是在mounted里有两次渲染。
而由于Vue内部的渲染机制,实际上页面只会渲染一次,把第一次的赋值所带来的的响应与第二次的赋值所带来的的响应进行一次合并,将最终的val只做一次页面渲染。
异步渲染,回顾$nextTick,如果data的修改,一次更新视图,减少dom操作次数来提高性能
七、axios发送网络请求
文档:https://www.kancloud.cn/yunye/axios/234845
axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和node.js中。axios是vue作者推荐使用的网络请求库,大白话:promise封装的ajax,它具有以下特性:
支持浏览器和node.js
支持promise
能够拦截 请求和响应
自动转换json数据
axios的浏览器支持
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3WKDlGK-1685269742852)(img\1624666492443.png)]
性attach到DOM树上,通知浏览器去执行绘制工作,这样可以避免大量的无谓的计算量。
优点:
-虚拟DOM具有批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染,优化性能.
缺点:
-首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
vue 首屏时间长,白屏问题。
dom和虚拟dom对比
如何将虚拟dom转为真实dom基本操作?
//dom
<ul id='test' class="header">
<p class='hehe'>这里是p标签</p>
</ul>
//对应的虚拟dom对象
let vdom={
tag:'ul',
attr:{
id:'test',
class:'header'
},
content:[
{
tag:'p',
attr:{
class:'hehe'
},
content:'这里是p标签'
}
]
}
作业:手写一个虚拟dom?[笔试题]
diff算法如何进行比较的?
[外链图片转存中…(img-SztFVTdC-1685269742851)]
diff->只比较同一层级,不跨级比较,tag不相同直接删掉重建不在深度比较,tag和值两者都相同,则认为是相同节点,不在深度比较
模板编译
vue模板是什么东西?
vue模板,他不是html,有指令,插值,js表达式,能实现判断,循环,html是标签语言,只有js才能实现判断,循环,vue他通过vue template complier将模板编译为render函数,执行render函数生成vnode,在渲染和更新。(react一直用render函数,没有模板)
异步渲染
[外链图片转存中…(img-ITvo50vQ-1685269742851)]
上面这一段代码中,在mounted里给val属性进行了两次赋值,如果页面渲染与数据的变化完全同步的话,页面应该是在mounted里有两次渲染。
而由于Vue内部的渲染机制,实际上页面只会渲染一次,把第一次的赋值所带来的的响应与第二次的赋值所带来的的响应进行一次合并,将最终的val只做一次页面渲染。
异步渲染,回顾$nextTick,如果data的修改,一次更新视图,减少dom操作次数来提高性能
七、axios发送网络请求
文档:https://www.kancloud.cn/yunye/axios/234845
axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和node.js中。axios是vue作者推荐使用的网络请求库,大白话:promise封装的ajax,它具有以下特性:
支持浏览器和node.js
支持promise
能够拦截 请求和响应
自动转换json数据
axios的浏览器支持
[外链图片转存中…(img-z3WKDlGK-1685269742852)]