0%

vue2

0.0 课程介绍

  • Vue介绍 【了解】
  • Vue项目的搭建 【掌握】
  • 项目目录详解【掌握】
  • Vue组件化【掌握】
  • Vue的表达式 【重点】
  • Vue的指令【重点】

1.0 什么是Vue?【了解】

Vue是一个构建用户界面(UI)的JS库。

1.1Vue的特点

  • 小 20k 【大概11000多行】
  • 性能强 虚拟dom
  • 双向绑定
  • 生态丰富

1.2 Vue历史 [了解]

1.0 -> 2015.10

2.0 -> 2016.10 https://v2.cn.vuejs.org/v2/guide/installation.html

3.0 -> 2020.09 https://cn.vuejs.org/

2023年5月20日 :3.3.4

2.0 Vue的环境搭建【掌握】

2.1 CDN使用

  • 直接使用网络资源
  • 将vuejs下载到本地

2.2 脚手架安装

先安装Vue脚手架

1
2
3
4
5
6
vue --version // 查看脚手架的版本

安装:
npm i @vue/cli -g

yarn add global @vue/cli

#注意 如果你的yarn无法使用,可能是没有安装yarn npm i yarn -g,或者是没有配置环境变量

yarn global bin 找到你的yarn安装位置

我的电脑-> 右键属性 -> 高级系统配置 ->环境变量 -> path、

2.3 使用脚手架创建Vue的项目

1
vue create 项目名      // vue-demo    demo

一顿操作

见图形笔记

#如果你想删除你保存预设方案,去我的电脑->用户 ->你的电脑名 ->删掉 vuerc

C:\Users\你的电脑名

3.0 组件化【掌握】

3.1 什么是组件化?

相当于将一个大的页面拆分成多个大组件,通过小组件组合成大组件,这个用组件拼接成页面的思维就叫组件化

特点:

  • 可复用
  • 易维护
  • 可组合

3.2 单文件组件

一个.vue文件就是一个单文件组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template> // 你的html
<div>
不仅可以写样式,还可以写很多vue提供的语法及指令
...
</div>
</template>


<script> // 你的js
// 你在此处暴露了什么出去? VueComponent类
export default {
// 你的VUE配置选项
data(){ // 专门放你的数据
return {
xx
}
},

methods:{ // 专门放你的方法们
fn(){ },
foo(){ },
}

}

</script>

<style lang="less" scoped> // 写你的css

</style>

注意: 推荐插件

vuter: 语法提示

Vue VSCode Snippets : 快捷键

path: 路径提示

4.0 Mustache胡须表达式【重点】

1
2
3
4
5
6
7
8
9
10
11
{{ 表达式 }}
`${ 表达式 }`

看是不是表达式?
100 // 是
let arr = [10,20,30]
arr.map(v=>v+100).join('-') // 是
true?'不是''是' // 是
if(true){ a = 10 } // 不是
for(let i=0;i<10;i++){ a+=i } // 不是
arr.forEach(i=>{ i+10 }) // 不是

什么是表达式

1、能够得到唯一结果的一句运算

2、可以放在赋值表达式右侧

5.0 指令 【重点】

vue的指令是什么?

帮助我们操作dom,提高效率

vue的指令就是一个以v-开头的自定义属性

1
<div id="dxx" class="xxx" age="10" v-xx="表达式">

5.1 v-text 和 v-html

作用:帮助我们渲染dom节点

v-text: 底层是 textContent ,渲染数据,不能识别标签

v-html: 底层是 innerHTML ,渲染数据, 能够识别标签

5.2 v-if 和 v-show

作用: 帮助我们根据条件渲染页面节点

v-show: 底层是通过控制display的属性来进行显示隐藏

v-if: 底层是通过删除页面或重新渲染节点来实现显示隐藏

5.3 v-if 和 v-else-if 和 v-else

作用: 帮助我们根据条件渲染页面节点,跟我们js中的if…else if…else是一样的用法,如果从上到下开始判断,当满足条件就不渲染后面的内容

5.4 v-for 循环

作用 : 帮助我们循环渲染页面

1
2
3
4
5
6
7
8
9
10
11
12
13
// 数组
let arr = [1,2,3]

<div v-for="(item,index) in arr"> // item 是你的每一项 index是你的索引
{{ item }} -- {{ index }}
</div>


// 对象
let obj = {name:'张无忌',age:18,like:'金花宝宝'}
<div v-for="(value,key,index) in obj">
{{ value }} -- {{ key }} -- {{index}}
</div>

5.5 v-model

作用:实现数据的双向绑定,只用使用v-model 与data里的数据就不分彼此 表单之王

1
2
<input v-model="data的数据" />

5.6 v-on 事件

作用:绑定事件, 简写为@

1
2
3
4
5
6
7
8
9
常规写法:
<button v-on:事件类型=“表达式”>xxx</button>
<button v-on:事件类型=“处理函数”>xxx</button>
<button v-on:事件类型=“处理函数(参数1,参数2,...)”>xxx</button>

简写:
<button @事件类型=“表达式”>xxx</button>
<button @事件类型=“处理函数”>xxx</button>
<button @事件类型=“处理函数(参数1,参数2,...)”>xxx</button>

0.0 自定义组件的使用 【掌握】

  • 引入组件
1
2
import 组件名 from '路径/文件名'

  • 注册组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
export default {
components:{ // 组件注册
组件名:组件名,
组件名1
},
data(){ // 数据
return {}
},
methods:{ // 方法

}

}

</script>


  • 使用组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <template>
    <div>
    <组件名></组件名>
    <组件名 />

    <!-- 使用组件 -->
    <CommonHeader></CommonHeader>
    <CommonContent />
    <CommonFooter></CommonFooter>

    <!-- 第二用法 推荐-->
    <common-header></common-header>
    <common-content />
    <common-footer />
    </div>
    </template>


1.0 课程介绍

  • v-bind 动态绑定属性 【重点】
  • 其他指令 【了解】
  • 计算属性computed 【重点】
  • 过滤器 filters 【掌握】
  • 侦听器 watch 【掌握】
  • Vue生命周期 【掌握】

2.0 v-bind 【重点】

作用:帮助我们操作节点属性,让属性变成数据驱动

1
2
3
4
5
6
7
8
9
<标签 v-bind:class='表达式'  v-bind:style="表达式" v-bind:src="表达式">
</标签>

简写:

<标签 :class='表达式' :style="表达式" :src="表达式">
</标签>


3.0 其他指令 【了解】

3.1 v-pre

作用:不编译胡须表达式

3.2 v-once

作用:只渲染一次,当他所依赖的数据发生改变时,也不会更新渲染

3.3 v-cloak

作用:隐藏胡须表达式,直到有数据时才渲染,只有直接在项目里引入vuejs才会出现,当前主流脚手架版本没有这个问题

4.0 computed 计算属性 【重点】

用于一堆逻辑计算,返回一个唯一的结果 ,与methods定义方式一样,计算属性直接使用他的函数名(不需要加小括号),就等于他的返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
{{ 函数名 }}
</div>
</template>
<script>
export default {
....
computed:{
函数名(){
一堆的逻辑运算

return '最终的结果'
}
}
}
</script>


计算属性的特点:

  • 计算属性用于一堆逻辑运算,直接使用函数名就等于使用了最终结果
  • 计算属性依赖的数据发生改变,他就会重新计算
  • 计算属性存在依赖缓存,性能强,如果依赖的数据更新就会重新计算,如果不更新就直接返回上一次的计算结果

computed计算属性 与 methods方法的区别 【面试题】

  • computed计算属性必须有返回值,methods不一定有
  • 调用方式不一样,computed计算属性直接使用函数名,methods方法需要函数名()调用
  • computed计算属性有依赖缓存,methods方法每次调用都会重新计算结果,计算属性如果数据没有改变,他就将上一次缓存的结果直接返回,就不重新计算了

5.0 filters 过滤器【掌握】

作用:用于处理页面数据的显示格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div>

{{ msg | 过滤器函数名 }}
</div>
</template>
<script>
export default {
data(){
return {
mes:'xxx'
}
},
methods:{},
components:{},
computed:{},
filters:{
过滤器函数名(参数){
一堆参数的处理
return '处理完的结果'
}

}


}

</script>


6.0 侦听器 watch 【掌握】

作用:用于监听数据的变化,进行相应函数的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div>

{{ msg | 过滤器函数名 }}
</div>
</template>
<script>
export default {
data(){
return {
msg:''
}
}
watch:{
需要监听的数据(newVal,oldVal){
// 一堆的后续操作
}
},


}

</script>




7.0 生命周期 【重点】

什么是生命周期?

是指组件从创建到渲染到更新到销毁的周期过程

vue的声明周期分为4大阶段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#注意:他们都是内置选项
// 创建前后
beforeCreate(){}, // 创建前 组件实例对象还没有创建,data里的数据不能访问
created(){}, // 创建后 ******* 组件实例已经创建完毕,data里的数据可以访问,此时页面dom还没挂载
#注: created 一般用于初始化页面数据发送ajax
// 挂载前后
beforeMount(){} // 挂载前 生成虚拟dom,页面dom还没有挂载
mounted(){} // 挂载后 ******* 页面dom已经挂载完毕,可以操作dom
#注: mounted 一般用于操作dom节点
// 更新前后
beforeUpdate(){} // 更新前
updated(){} // 更新后
// 销毁前后
beforeDestroy(){} // 销毁前 ** 一般用于清除绑定事件、定时器
destroyed(){} // 销毁

总结:vue的生命周期的作用,在组件各个阶段执行相应的生命周期钩子函数,给用户添加自己代码的机会

作业:

1 购物车案例

2 交互代码敲3遍

3 面试题: 计算属性computed和方法methods有什么区别?

4 选做题:操作题

5 手写配置选项 和 指令

0.0 课程介绍

  • 组件通信【重点】
  • slot 插槽【掌握】
  • 封装组件【掌握】
  • UI组件库【掌握】

1.0 组件通信

组件为了实现交互,通过数据传递实现,这个就叫做组件通信

自定义组件的使用:

  • 引入组件
  • 注册组件
  • 使用组件

1.1组件通信类型:

  • 父传子【重点】: 在父页面的子组件标签上定义需要传递参数,在子组件页面通过配置选项props 进行接收参数,使用方法与data里的数据一样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<template>
<son 参数1=“表达式” :参数2=“msg12”></son>
</template>
<script>
import Son from 'xx/Son.vue' // 引入组件

export default{
// 注册组件
components:{ Son },
data(){
return {
msg:'xxx'
}
}
}
</script>


# 子组件接收参数
<template>
<div>
{{ msg }}
{{ 参数1 }}
</div>
</template>
<script>
// 子组件接收父组件传入的参数
export default{
// 数组接收方法1
props:['参数1','参数2']

// 对象接收方法2 【推荐】
props:{
参数1:{ // 配置选项
required:true, // 是否必传
type:String|Number|Boolean|Object|Array, // 数据类型:构造函数
default:''|0|false
// 注意:如果类型为引用类型 ()=>{return {}}、()=>{return []}
}
},
data(){
return {
msg:’xxx‘
}
}
}
</script>


  • 子传父【重点】:vue是单向数据流,子组件不可以直接修改父组件传入的数据,只能通过触发事件进行数据修改;

    发送:通过this.$emit(‘自定义事件名‘,参数),将参数传递给父组件;

    接收:父组件页面在子组件的标签上绑定自定义事件名接收传入参数;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# son.vue
<template>
<div>
...内容
<button @click="处理函数"> 修改 </button>

</div>
</template>
<script>
export default{
...
// 方法
methods:{
处理函数(){
// 通过$emit触发自定义事件,携带对应参数给父组件
this.$emit('自定义事件名',参数1,参数2...)
}
}
}

</script>


#父组件
<template>
<son 参数1=“表达式” :参数2=“msg12” @自定义事件名="处理函数"></son>
</template>
<script>
import Son from 'xx/Son.vue' // 引入组件

export default{
// 注册组件
components:{ Son },
data(){
return {
msg:'xxx'
}
},
// 方法
methods:{
处理函数(参数1,参数2){
// 处理逻辑后修改数据
this.msg = 参数1
}
}
}
</script>

  • 乱传(中央事件总线bus)【理解】: 找一个Vue实例当中介,通过这个中介进行数据的传递和接收

    特点: 用起来非常简单,缺点就是乱,维护成本极高

1
2
3
4
5
6
7
8
9
1、创建中介 -- 创建vue的实例 挂载到Vue的原型上
Vue.prototype.$bus = new Vue()
2、传递信息
this.$bus.$emit('自定义事件名',参数)
3、接收信息
created(){
this.$bus.$on('自定义事件名',(参数)=>{ // 处理数据 })
}

父子关系确定: 如果你在我的页面引入,注册,使用,那么我就是你爸爸

  • 依赖注入【不讲】:祖先组件注入某个属性,在子孙组件依赖这个变量
  • vuex 状态管理库
  • 插槽 :他传递元素
  • 路由传参: Router

2.0 插槽的基本使用 【掌握】

在子组件里挖坑,在父组件使用时填坑就可以了,这就是插槽的作用

2.1 插槽的类型

  • 匿名插槽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#子组件 son.vue
<template>
<div>
<slot></slot>
</div>
</template>

#父组件 father.vue
<template>
<div>
<son>
写入你想写内容包括元素标签
</son>
</div>
</template>

  • 具名插槽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#子组件 son.vue
<template>
<div>
<slot name='插槽名1'></slot>
<slot name='插槽名2'></slot>
</div>
</template>

#父组件 father.vue
<template>
<div>
<son>
<写入你想写内容包括元素标签 slot="插槽名2" />
<写入你想写内容包括元素标签 slot="插槽名1" />
</son>
</div>
</template>

  • 作用域插槽 (相当于将子组件的数组 传给父组件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#子组件 son.vue
<template>
<div>
<slot name='插槽名1' :需要传出去的属性1=“属性值1” :需要传出去的属性2=“属性值2” ></slot>
<slot :需要传出去的属性1=“属性值1” :需要传出去的属性2=“属性值2”></slot>
</div>
</template>

#父组件 father.vue
<template>
<div>
<son>
# 具名插槽
<写入你想写内容包括元素标签 slot="插槽名1" slot-scope="scoped">
{{ scoped }}
</写入你想写内容包括元素标签>
# 匿名插槽
<写入你想写内容包括元素标签 slot-scope="scoped" >
{{ scoped }}
</写入你想写内容包括元素标签>

</son>
</div>
</template>

3.0 组件库的使用

去相应的官网找到合适的组件, C + V

  • 根据你选择的元素,查看对应的属性、方法、事件文档

ElementUI (https://element.eleme.cn/#/zh-CN)

1
2
3
4
5
6
7
8
9
10
11
1、下载
npm i element-ui -S

yarn add element-ui -S

2、引入及使用(在main.js引入)
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

Vant UI (https://vant-contrib.gitee.io/vant/v2/#/zh-CN/)

1
2
3
4
5
6
7
8
9
10
11
1、下载
npm i vant@latest-v2 -S

yarn add vant@latest-v2 -S

2、引入及使用(在main.js引入)
import Vant from 'vant'; // js
import 'vant/lib/index.css'; // css

Vue.use(Vant);

0.0 课程介绍

  • Vue 路由库Router 【重点】

    • 安装
    • 基本使用
    • 路由配置
    • 路由模式
    • 路由传递参数
    • 路由内置对象
    • 路由守卫
  • Vue的内置API 【掌握】

    • ref

    • Vue.set

    • Vue.nextTick

    • Vue.filter

    • Vue.component

    • Vue.use

    • Vue.directive

1.0 Vue的路由Router 【重点】

1.1 路由作用

进行页面的跳转(相当于a标签),Vue是SPA单页面应用,他的页面跳转必须使用Vue-Router路由进行实现

1.2 路由的安装

vue create 项目名 创建一个带有Vue路由的项目

1.3 路由的使用

一级路由配置

  • 1 建(建大页面)
  • 2 配 (配置路由选项,一一对应)
  • 3 给出口及测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
如果你的页面需要进行路由显示,必须给出口 <router-view></router-view>,一级路由出口在App.vue页面,嵌套路由出口在父页面
路由出口:就是你页面需要渲染的位置
测试:在浏览器路径输入对应path


// 配置路由列表
const routes = [
{ path: '/', redirect: '/discover' }, // redirect: 重定向指定的路由(一级路由)
// 配置一级路由
{ path: '/discover', component: DiscoverView },
{ path: '/my', component: MyView },
{ path: '/friend', component: FriendView },
]

  • 4 配置导航
1
2
3
4
<router-link to="/discover">发现音乐</router-link>
<router-link to="/my">我的音乐</router-link>
<router-link to="/friend">关注音乐</router-link>

嵌套路由配置

  • 1 建 (建大页面)
  • 2 配 (配置路由选项,一一对应)
  • 3 给出口及测试
1
2
3
4
5
6
7
8
9
10
11
12
13
嵌套路由的出口在父页面 <router-view></router-view>

{
path: '/discover', component: DiscoverView,
redirect: '/discover/toplist', // redirect: 重定向指定的路由(嵌套路由)
// 配置嵌套路由
children: [
{ path: '/discover/recommend', component: RecommendView },
{ path: '/discover/toplist', component: ToplistView },
{ path: '/discover/playlist', component: PlaylistView },
]
},

  • 4 配置导航
1
2
3
4
5
6
7
8
9
<div class="discover">
<!-- 嵌套路由的出口在父页面 -->
<router-link to="/discover/recommend">推荐</router-link>
<router-link to="/discover/toplist">排行榜</router-link>
<router-link to="/discover/playlist">歌单</router-link>
<!-- 嵌套路由的出口 -->
<router-view></router-view>
</div>

1.4 路由的模式 【重点】

【面试题】

  • hash模式 :地址栏带#, 底层实现的是用 onhashchange的一个方法

  • history模式 : 地址栏不带#,底层实现是用的h5的 pushState 方法

    区别:

    [1] : 地址栏一个带#,一个不带#

    [2] : 底层实现的原理不一样

    [3] : hash模式根history模式在开发中没有任何区别,但是在打包后的代码hash模式没有问题,history模式会存在刷新后页面丢失情况

    #解决办法: 只能让后端或者运维,对nginx代理服务器进行相应重定向的配置

1.5 路由的传参 【掌握】

  • query传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 路由提供了一个跳转的方法 this.$router.push('/路径')
// query配置项
1、路由跳转
this.$router.push({
path:'/路径',
query:{
键名:键值,
键名1:键值1,
}
})
2、获取参数
this.$route.query

特点:
1、页面刷新参数依旧存储
2、不能直接传递引用类型(可以用JSON.stringify 转成字符串【不推荐】)

  • params传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 路由提供了一个跳转的方法 this.$router.push('/路径')
// params配置项
1、路由跳转
this.$router.push({
name:'路由名',
params:{// 并且可以携带引用类型
键名:键值,
键名1:键值1,
}
})
2、获取参数
this.$route.params

特点:
1、页面可以携带引用类型
2、刷新页面数据丢失(将刷新按钮禁用或者去除)

  • 动态路径传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 路由提供了一个跳转的方法 this.$router.push('/路径')
1、路由配置项中进行路径动态传参配置
{ path: '/my/:变量名', component: MyView },
2、路由跳转
this.$router.push({
path:'/my/传入的值'
})
3、获取参数
this.$route.params

特点:
1、刷新页面后不会丢失数据
2、动态路径必须携带参数

1.6 路由的两个内置对象【掌握】

  • $router

路由实例对象,他主要提供一些页面跳转的方法(他其实就等 === VueRouter)

​ push

​ go

replace

  • $route

路由信息对象,他主要提供当前页面的参数信息

params

query

path

1.7 路由守卫【理解】

全局前置路由守卫,监听路由变换,判断是有权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
router.beforeEach((to,from,next)=>{
// to 你要去往哪里
// from 你从哪里来
// next 是个函数,如果直接调用就可以前往,如果传入路径,就前往指定页面
})

router.beforeEach((to, from, next) => {
// 如果我跳转目标是我的,那我就让你重定向关注
if (to.path == '/discover/recommend') {
next({ path: '/discover/playlist' })
} else {
next()
}

// const token = localStorage.getItem('token123')
// if (!token) {
// next({ path: '/login' })
// } else {
// next()
// }
})

2.0 Vue的内置API【掌握】

2.1 ref

作用:用于获取Dom节点,相当于元素选择器,如果你获取的是子组件,相当于获取到自组件的实例对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>
#dom
<span ref="ref的值1">dom节点</span>

#子组件
<son ref="ref的值2"></son>
</div>
</template>

<script>
export default {
methods:{
init(){
this.$refs.ref的值1 #DOM节点
this.$refs.ref的值2 #子组件的实例对象
}
}
}
</script>
定义ref的值: 在父页面的子组件(或dom)标签上定义属性ref=“ref的值”
获取ref的值: 在js中通过this.$refs.ref的值 来获取子组件实例(或dom节点)


2.2 Vue.set

他可以帮助我们重新挟持【绑架】数据,让数据具备响应式

理论【面试题】:因为Vue底层会对data里进行挟持,当初始状态对象没有这个属性,后期添加的属性没有被挟持,不具备响应式,通过Vue.set方法让数据重新挟持

1
2
3
4
5
6
import Vue from 'vue'
Vue.set(需要挟持的对象, "属性", "修改的值");

this.$set(需要挟持的对象, "属性", "修改的值")


数组怎么改?

解决方法:数组的变更方法,这是被Vue重写的方法,可以让数组里的数据修改时也具备响应式

1
2
3
4
5
6
7
8
9
10
11
push()
pop()
shift()
unshift()
splice()
sort()
reverse()

以上方法已经升级啦


2.3 Vue.nextTick

他是一个回调函数,帮你解决异步的问题,在下一次页面节点更新完毕后触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import Vue from 'vue'
Vue.nextTick(()=>{
// 下一次页面节点更新完毕后触发
})

this.$nextTick(()=>{
// 下一次页面节点更新完毕后触发
})

created() {
// 本身created是拿不到dom节点
console.log(document.querySelector("#msg"));
// 但是nextTick是下一次dom更新后触发 ,就相当于mounted时触发回调函数
Vue.nextTick(() => {
console.log(document.querySelector("#msg"));
});

this.$nextTick(() => {
console.log(document.querySelector("#msg"));
});
}


2.4 Vue.filter

全局过滤器,注册的全局过滤器可以在任何页面使用

1
2
3
4
5
6
7
8
9
#main.js

Vue.filter('过滤器的名字',(参数)=>{
// 一堆格式处理的逻辑
return ’过滤后的结果‘
})



2.5 Vue.component

注册全局组件

1
2
3
4
5
// 全局组件
Vue.component('Counter', Counter)



2.6 Vue.use

使用插件,当插件是基于Vue.js写的,就需要use一下

1
2
3
4
5
6
7
8
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

// 因为ElementUI底层是基于Vue.js写的 所以需要Vue.use使用一下
Vue.use(ElementUI);


2.7 Vue.directive

自定义的指令,可以根据自身需求自己定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Vue.directive('指令名',{
// 里面有很多的配置
bind #只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted #被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

})

Vue.directive('overflow', {
inserted: (dom, obj) => {
// 截取 溢出隐藏
dom.style.width = obj.value + 'px'
dom.style.overflow = 'hidden'
dom.style.whiteSpace = 'nowrap';
dom.style.textOverflow = 'ellipsis';
}
})


作业

2 • 配置Fitness健身项目的路由(一级路由 和 二级路由)。

3 代码练习

4 xmind

5 下节课过一眼

0.0 课程介绍

  • Vuex 【掌握】
  • 页面懒加载
  • 组件懒加载

1.0 Vuex 状态管理库

Vuex是一个Vue的插件,用于管理状态( 数据 )

Vuex作用场景:

  • 祖先组件向子孙组件传递数据,层级非常深

  • 多个组件间的数据共享

Vue的核心功能

核心State

用于注册、存放数据的仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default new Vuex.Store({
// 存储状态(数据)
state: {
num: 250,
goods: [
],
// 白马会员列表
whiteHorseVip: [
{ name: '凯子哥', age: 24 },
{ name: '黄子姐', age: 22 },
{ name: '维子哥', age: 26 },
{ name: '俊子哥', age: 18 }
]
}
})


1、直接获取仓库的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div>
<div>num:{{ $store.state.num }}</div>
<div>
goods:
<p v-for="item in $store.state.goods"
:key="item.name"
>{{ item.name }} --{{ item.price*item.count }}</p>
</div>
</div>
</template>

<script>
export default {
created() {
console.log(this.$store.state.num);
},
// 推荐
computed: {
num() {
return this.$store.state.num;
},
goods() {
return this.$store.state.goods;
}
},
};
</script>


2、通过辅助函数获取仓库数据

mapState 特点:map 映射 State仓库 : 与仓库里的state一一对应

1
2
3
4
5
6
7
8
9
10
11
12
13
import {mapState} from 'vuex'
export default{
computed:{
// 辅助函数的数组写法
...mapState(['要取变量1''要取变量2']), 【强烈推荐】
// 辅助函数对象写法
...mapState({
key:(state)=>state.要取变量1,
key1:(state)=>state.要取变量2,
})
}
}

核心Mutations

用于修改仓库数据的唯一方法,如果要修改仓库的数据必须提交一个mutation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 定义修改的方法,mutation
export default new Vuex.Store({
// 存储状态(数据)
state: {
num: 250,
goods: []
},
// 修改数据的唯一方法,如果要修改状态必须提交一个mutation
mutations: {
// 定义一个修改mutation - 函数名一般为全大写
函数名(state,payload){
state.goods = payload
}
},
})


// 在你的页面直接提交mutation变化,用于修改仓库的数据
this.$store.commit('函数名',实参)
this.$sotre.commit({ 【不推荐】
type:'函数名',
data:实参
})

// 通过辅助函数提交mutation
import {mapMutations} from 'vuex'

export default{
methods:{
// 辅助函数的数组写法
...mapMutations(['函数名'])
// 辅助函数的对象写法
...mapMutations({
key:'函数名1',
key2:'函数名2'
})
}

}

核心Getters

相当与状态管理库的计算属性,对state进行二次处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 定义getter处理方法
export default new Vuex.Store({
// 存储状态(数据)
state: {
num: 250,
goods: [
],
// 白马会员列表
whiteHorseVip: [
{ name: '凯子哥', age: 24 },
{ name: '黄子姐', age: 22 },
{ name: '维子哥', age: 26 },
{ name: '俊子哥', age: 18 }
],

},
// vuex里的计算属性
getters: {
// 把数据进行二次处理
whiteHorseVipList(state) {
return state.whiteHorseVip.filter(v => v.age > 18)
}
}
})

// 在页面获取getters里的属性
<template>
<div>
<div>num:{{ $store.getters.whiteHorseVipList }}</div>
<div>
goods:
<p v-for="item in $store.getters.whiteHorseVipList"
:key="item.name"
>{{ item.name }} --{{ item.age }}</p>
</div>
</div>
</template>

<script>
export default {
// 推荐
computed: {
whiteHorseVipList() {
return this.$store.getters.whiteHorseVipList;
}
},
};
</script>

// 辅助函数获取getters属性
import {mapGetters} from 'vuex'
export default{
computed:{
// 辅助函数的数组写法
...mapGetters(['whiteHorseVipList'])
}
}

核心Actions

用于异步修改数据,但是最终修改数据还是需要调用mutation方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 在仓库中定义actions
export default new Vuex.Store({
// 存储状态(数据)
state: {
num: 250,
},
// 修改数据的唯一方法,如果要修改状态必须提交一个mutation
mutations: {
SET_NUM(state, payload) {
state.num += payload
}
},
// 处理异步修改数据,最终也要提交一个mutation
actions: {
asyncSetNum(context, payload) { // context === new Vuex()
return new Promise(reslove => {
// 异步操作
setTimeout(() => {
context.commit('SET_NUM', payload)
reslove()
}, 2000);

})
}
},
})

// 在页面触发actions的方法

// 直接触发
this.$store.dispatch('函数名',实参)
this.$store.dispatch({ 【不推荐】
type:'函数名'',
data:'实参'
})

// 辅助函数
import {mapActions} from 'vuex'
export default{
methods:{
// 数组写法
...mapActions(['函数名']),

// 对象写法
...mapActions({
键名:'函数名'
})
}
}

核心modules

模块化,拆分你的仓库

1 定义模块化的仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
export default new Vuex.Store({

// 模块,把仓库拆分成多个
modules: {
moduleA: {
namespaced: true,
state: {
money: 1000000
},
getters: {},
mutations: {},
actions: {}
},
moduleB: {
namespaced: true,
state: {
money: 10
},
getters: {},
mutations: {},
actions: {}
}
}
})


2 获取模块化里的状态(数据)

1
2
3
4
// 直接获取
this.$store.state.模块名.属性名;
// 辅助函数获取

修改模块里的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<div>
home
<h1>moneyA:{{ moneyA }}</h1>
<h1>moneyB:{{ moneyB }}</h1>

<div>money:{{ money }}</div>
<button @click="SET_MONEY(100)">改变</button>
<button @click="update">直接改变</button>
</div>
</template>

<script>
import { mapState, mapMutations } from "vuex";
export default {
created() {
console.log(this.$store);
},
computed: {
// 辅助函数mpaState获取模块里的数据
...mapState("moduleA", ["money"]),
moneyA() {
// 直接获取modelA里state的属性
return this.$store.state.moduleA.money;
},
moneyB() {
// 直接获取modelB里state的属性
return this.$store.state.moduleB.money;
}
},
methods: {
// 模块化里获取辅助函数
...mapMutations("moduleA", ["SET_MONEY"]),
update() {
// 直接调用模块化里的方法
this.$store.commit("moduleA/SET_MONEY", 200);
}
}
};
</script>



0.0 课程介绍

  • 动态组件 【掌握】
  • 修饰符 【掌握】
  • 混入mixins 【掌握】
  • 内置组件 【理解】
  • v-model 【理解】
  • 路由懒加载和组件懒加载(异步组件) 【掌握】
  • 递归组件 【了解】
  • Vue底层:MVVM架构模式 【理解】
  • 虚拟DOM 【了解】

#目标:希望把知识点总结话术,能够大概的说出相应的理论

1.0 动态组件

通过内置组件component 的属性is 进行组件的动态渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<component :is="flag?Counter:HelloVue"></component>
<button @click="flag = !flag">取反{{ flag }}</button>
</div>
</template>

<script>
import Counter from './components/Counter.vue'
import HelloVue from '@/views/components/HelloVue.vue';
export default {
data(){
return {
flag:false,
Counter:Counter,
HelloVue
}
}
}
</script>


2.0 Vue修饰符

2.1 事件修饰符

.stop // 帮助你阻止事件冒泡

.prevent // 阻止默认行为

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<div class="box1" @click="handleBox1">
// 阻止冒泡及默认行为
<a class="box2" @click.stop.prevent="handleBox2" href="https://www.baidu.com"></a>
</div>
// 阻止默认行为
<a href="https://www.baidu.com" @click.prevent>点我</a>
</div>
</template>


2.2 按键修饰符

•.enter // 输入回车时触发

•.space // 输入空格时触发

• .up 上

• .down 下

• .left 左

• .right 右

document.body.addEventListener(‘keyup’,(e)=>{console.log(e.keyCode)}) // 获取你输入的按键码

2.3 表单修饰符

.lazy // 将v-model输入事件从input改变成change事件

.number // 将输入的数据转换为number类型

.trim // 去除输入数据的首尾空格

2.4 .sync修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
# 父页面
<template>
# 注意: .sync === @update:value="msg = $event"
<div>
.sync修饰符{{ msg }}
<!-- <son :value="msg" @update:value="msg = $event"></son> -->
<son :value.sync="msg" ></son>
</div>
</template>

#子页面
this.$emit('update:value','嘿嘿')

3.0 mixins混入 【掌握】

可以抽取公共的配置选项,然后混入到你需要的页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# mixin.js
export default {
data(){
return {
user:{name:'金花宝宝'}
}
},
methods:{
updateUser(){
this.user.name= '张无忌'
}
}
}

#在你需要混入的页面使用

<script>
import mixin from '@/mixins/mixin'
export default {
// 配置选项
mixins:[mixin],
data(){
return {
age:18
}
},
methods:{
getData(){
console.log('嘿嘿');
}
}
}
</script>


4.0 Vue内置组件

  • slot : 插槽
  • componet : 动态组件
  • transition : 过渡动画
1
2
3
4
5
6
7
8
9
10
11
12
13
<transition name="动画名">
// 里面放有dom操作的dom节点
<div v-show v-if></div>
</transition>

// 动画效果
.动画名-enter-active, .动画名-leave-active {
transition: opacity .5s;
}
.动画名-enter, .动画名-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}

  • keep-alive 缓存组件
1
2
3
4
5
6
7
8
9
<keep-alive include="['组件名a', '组件名b']" :max="20" :exclude="['不缓存的组件名','不缓存的组件名']">
// 包裹住你的出口 app.vue
<router-view></router-view>
</keep-alive>

:include="['组件名a', '组件名b']"
:exclude="['不缓存的组件名','不缓存的组件名']"
:max="20" 你最多缓存的组件数量

5.0 自定义的v-model

实现自定义v-model的方法

1、组件接收值的属性value

2、组件内修改这个值的自定义事件名为input

修改v-model的默认配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<div>
<!-- 将默认的属性从value改成heihei 将默认的事件从input改成change -->
<select :value="heihei" @change="inputData">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
</select>
</div>
</template>
export default {
model: {
prop: 'heihei',
event: 'change'
},
props:{
// 接收的属性value
heihei:{
type:String,
default:0
}
},
methods:{
inputData(e){
console.log(e.target.value);
// 输出的事件名 input
this.$emit('change',e.target.value)
}
}
}

6.0 路由懒加载 和 组件懒加载(异步组件)

路由懒加载的作用:

只会根据输入路径之后,再进行针对性组件页面加载,提高首屏加载速度

1
2
3
4
5
6
{
path: '/sync-modifier',
name: 'sync-modifier',
component: () => import('../views/02-.sync修饰符.vue')
}

组件懒加载(异步组件)

在页面渲染到指定位置才开始加载对应的组件

1
2
3
4
5
components:{
MyInputNumber:()=>import('./components/MyInputNumber.vue')
},


7.0 递归组件 【理解】

组件自己调用自己

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<ul >
<li v-for="item in dataList" :key="item.name">{{ item.name }}
<my-menu :dataList="item.children"></my-menu>
</li>
</ul>
</div>
</template>

<script>
export default {
name:'MyMenu',
props:{
dataList:{
type:Array,
default:()=>[]
}
}
}
</script>


8.0 MVVM的底层原理

M:Model 数据模型,主要是提供数据

V: View 视图,主要用于渲染页面

VM: ViewModel视图模型 , 他是连接 M 和V的桥梁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Model
const data = {
message:'这是初始的值'
}

// View
function render(){
document.querySelector('#app').innerHTML = `
<input value=${data.message} oninput="inputchange(this)"/>
${data.message}
`
}
render()

let val = data.message
// ViewModel 是M 和 V之间的桥梁
// 有三个参数 参数1:需要挟持的对象 参数2:需要监听键名 参数3:是个对象,里面有两方法 get set
// 通过defineProperty 将所有操作(访问,修改),转换成get和set
Object.defineProperty(data,'message',{
// 只要有人访问了挟持对象的那个属性就触发get
get(){
console.log('get');
return val
},
// 只要有人修改挟持对象的那个属性就触发set
set(newVal){
console.log('set');
val = newVal
render()
}
})

// V 到 M 的方向
function inputchange(dom){
console.log(dom.value);
data.message = dom.value

}


9.0 虚拟DOM

虚拟是一个js的对象,vue中虚拟dom在beforeMount创建完毕,dom真实节点尚未挂载,当页面发生改变,再次创建一个新的虚拟dom,通过diff算法,将新老虚拟dom,进行比较差异,得到差异地方,进行针对性的局部渲染,大大提高了页面性能,减少不必要的消耗。

diff算法:

  • 深度优先原则
  • 同层比较原则

• v-for的key并不会在页面渲染,key就是提供给虚拟dom对比使用,优化性能.

作业

整理一份xmind, 包含6天所有vue的知识(并且回顾)

欢迎关注我的其它发布渠道