Vue3 + vite + Ts + pinia + 实战 + 源码 + ele
PBitW
编辑于 2024年05月17日 15:47

p2

vue2 -> 选项式 api

vue3 -> 组合式 api

1、双向绑定源码

小满Vue3(第一章 Vue3概述-梦开始的地方) P2 - 02:22 源码讲解

p10

响应式原理

为什么要换成proxy:

小满Vue3(进阶 响应式原理源码实现) P10 - 00:231、vue2对对象,只能劫持预先定义好的属性

2、vue2对数组,重写了数组原型的几个api,且无法监听修改某项值、length

都要使用$set

【object.defineProperty可以实现数组的修改,但是性能不好,了解】

2、优化VDom

小满Vue3(第一章 Vue3概述-梦开始的地方) P2 - 03:30

patch flag 做静态标记(通过位运算符,做枚举,每一个枚举就是一个状态),通过状态去更新!

3、fragment

1、template里面可以有多节点 ----》 vue自己给内容增加一个虚拟节点,但是不会渲染!

2、支持 jsx / tsx 的写法(类似react)

https://www.zhihu.com/question/436260027

3、新增加两个内置组件:Suspense、teleport 和 多 v-model用法

4、tree-shaking --》 import {} from vue

按需引入的意思,减小打包体积!

5、组合式 api

让内容不再分散

p3

node.js源码讲解

小满Vue3(第二章 环境搭建 底层介绍) P3 - 09:08

nodejs架构

libuv源码

小满Vue3(第二章 环境搭建 底层介绍) P3 - 11:04

p4

1、使用vite / ts项目的一些不同点

小满Vue3(第三章 认识目录&SFC&插件) P4 - 01:11

vite-env.d.ts -> ts不认识 .vue文件,所以声明一下扩充

vite是以index.html为文件入口,使用esm形式(type=‘module’)来引入main.js,引入时拦截去处理里面的东西!webpack是以main.js为入口文件

vite基于esbuild去做的编译,然后根据rollup进行打包的!

2、sfc --》 单文件组件

script 含setup只能出现一次,不含可以多个

style可以多个

最外层 template 只能有一个

3、npm run dev过程

小满Vue3(第三章 认识目录&SFC&插件) P4 - 04:38

依赖包的查找过程

node_nodules(看bin有没有vite可以执行) ->

去npm i -g(全局包里找) ->

环境变量 ->

报错

p5

vue3书写风格,支持3种:

1、兼容 vue2 的选项式写法

组合式

2、setup函数模式 -> 必须return

3、setup语法糖模式 -> script标签上加setup,不需要return

动态事件

小满Vue3(第四章 模板语法 & vue指令) P5 - 08:09

v-memo(不常用)

https://juejin.cn/post/7180973915580137527

接收数组 -> 数组里面有一个值(条件不成立才渲染,成立就会跳过更新);空数组就和v-once一样的

用法:

小满Vue3(第四章 模板语法 & vue指令) P5 - 17:52

p6

vue的虚拟Dom

ts --> js,babel的es6 --> es5,js通过v8引擎转字解码都会用 AST

小满Vue3(第五章 虚拟dom和diff算法) P6 - 01:05

为什么不直接操作dom,而是使用js描述dom?

因为在一个dom身上,属性很多,直接操作dom很消耗性能,但是操作js就很快,所以有了虚拟dom的概念!JS的计算性能来换取操作DOM所消耗的性能,既然我们逃不掉操作DOM这道坎,但是我们可以尽可能少的操作DOM。

虚拟 dom 会生成vnode

Diff算法

没有key的diff算法

源码:

小满Vue3(第五章 虚拟dom和diff算法) P6 - 04:07

c1旧的Vnode,c2新的Vnode

三步:

1、通过for,去替换元素

2、删除

3、新增

画图讲解:

小满Vue3(第五章 虚拟dom和diff算法) P6 - 04:50

有key的diff算法

画图讲解:

1、前序算法

小满Vue3(第五章 虚拟dom和diff算法) P6 - 07:28

2、尾序算法

小满Vue3(第五章 虚拟dom和diff算法) P6 - 07:59

源码:

1、前序算法

小满Vue3(第五章 虚拟dom和diff算法) P6 - 06:23

c1旧的Vnode,c2新的Vnode,新旧dom进行对比

五步:

1、前序算法

isSameVNodeType -> 判断type(元素类型)和key(绑定的key值)是否一致,如果一致就复用,不一样就跳出循环,进行下一步

2、尾序算法

3、首尾比完,多的新增 --》patch

4、少的就删除 --》unmount

5、特殊情况乱序(无序)

小满Vue3(第五章 虚拟dom和diff算法) P6 - 10:00

三部分:

5.1 构建新节点的映射关系

小满Vue3(第五章 虚拟dom和diff算法) P6 - 10:43

5.2 记录新节点在旧节点中的位置数组,多余的旧节点删除,新节点不包含旧节点也删了,如果节点出现交叉,说明是移动(moved = true),进行下一步

小满Vue3(第五章 虚拟dom和diff算法) P6 - 11:54

5.3 获取最长递增子序列(贪心+二分)去删除或者移动

小满Vue3(第五章 虚拟dom和diff算法) P6 - 13:10

vue2

双端diff算法 -> 头比头,尾比尾,头比尾、尾比头(交叉对比)

小满Vue3(第五章 虚拟dom和diff算法) P6 - 08:33

vue3做了优化,做了最长递增子序列算法

p7

1、ref() --》深层

注:

修改 / 取值必须使用 .value

2、isref() --》 判断是不是ref对象

3、shallowRef() --》浅层

.value才是响应的,再深一层就不行了!

eg:

注:

在一个setup中同时使用ref()和shallowRef(),shallowRef()也会深层改变!--》原因见4

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 07:36

4、triggerRef(响应式数据)

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 08:26

ref()底层更新的逻辑里,会调用triggerRef()

triggerRef()会强制更新收集(传入的值)的依赖

注意:

其实只要调用了ref(),不管是不是响应式数据,只要数据变了,都会重新渲染上去!

5、customRef()--》自定义ref

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 09:34

写法 --》 就是把收集 / 触发依赖的过程交给我们实现

function MyRef(value){

return customRef((track,trigger)=>{

return {

get(){

track();

return value;

},

set(newVal){

value = newVal

trigger();

},

}

})

}

注:

1、track()就是用来收集依赖的

2、trigger()就是用来触发依赖的

6、ref控制台技巧

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 13:46

7、ref()获取dom元素

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 14:46

直接给dom元素加一个ref

<div ref="xxx">xxx</div>

定义一个变量名,和dom上的ref一致

const xxx = ref()

console.log(xxx.value)

注:

setup时,dom还未渲染,不能打印,一般在事件中或者其他生命周期中使用!

8、ref()源码:

小满Vue3(第六章 Ref 全家桶 & 源码解析) P7 - 16:26

1、ref如果传递的是引用类型,会调用toReactive

2、是代理对象直接返回

3、shallowRef 给 createRef 传过去的就是true,所以不会走toReactive,所以传过去的对象、数组不会监听深层,但是.value会响应,因为还是会走依赖收集和更新

p8

1、ref()和reactive()区别

ref()、reactive()都不能直接赋值

reactive解决:

ref解决:

靠 .value. 赋值

2、readonly(xxx) --》只读【比较少用】

readonly会被原始的响应式数据影响,直接修改原始的响应式数据,readonly也变化了!

代码:

结果:

代码:

结果:

警告,且数据不变

3、shallowReactive()

和shallowRef()一样,浅层的,只到第一个属性!

代码:

结果:

界面不变,控制台变化

注:

和shallowRef一样,不能和reactive一起使用!

小满Vue3(第七章 Reactive全家桶 & 源码讲解) P8 - 11:57

4、reactive源码

小满Vue3(第七章 Reactive全家桶 & 源码讲解) P8 - 13:40

1、传入普通对象直接警告

2、如果是代理对象 或者 缓存里面找(缓存使用weakmap),直接返回

3、如果有__skip__属性,也直接返回

p9

a、toRef() --》 只能修改响应式对象的值

toRef(对象 , key)

1、非响应式数据改变,视图无变化

2、修改响应式对象的值

总结

把响应式对象的一个属性搞成ref类型单独给提出来使用

源码

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 11:51

1、ref源码会调用搜集和触发依赖,而toRef没调用,所以不会搜集和触发依赖更新 (因为reactive里面做了,这里再做就触发两次了,所以只对响应式数据有用)

2、通过对象和key获取到值,如果是响应式直接返回

b、toRefs() --》把响应式对象里面的每一个属性都改成ref

1、手写

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 05:39

2、使用--》解构

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 08:30

3、源码

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 13:58

c、toRaw()

把响应式对象变成原始对象

代码:

结果:

1、手写

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 11:07

实现:

响应式数据['__v_raw'] --》 vue里面没暴露的属性

2、源码

小满Vue3(第八章 toRef,toRefs,toRaw & 源码解析) P9 - 14:28

p10

p2有一部分

响应式原理手写

小满Vue3(进阶 响应式原理源码实现) P10 - 01:05

1、reactive封装,接收对象,使用get、set劫持,并在set、get中使用 Reflect(映射) 保证上下文,如果要监听深层,需要递归

2、这里的effect封装暂时就是一个更新dom的命令 可以不看

3、track 封装,接收 对象和key(下图中Map的name)

对象作为weakmap的key,value使用map定义,并要封装

最终实现

4、trigger封装,也是接收 对象和key,和上面一样,然后通过对象取Map,然后通过key得到effect

最终实现

p11

computed() --》 有缓存

1、选项式写法

2、函数写法 --》 不支持修改值

源码

小满Vue3(第九章 computed计算属性-精讲) P11 - 18:32

注意:

1、_dirty 脏数据标识,确认是否重新计算,默认true要计算

2、会参数归一化处理

3、computer 如果传参数了,那么就是methods,因为缓存没有了

手写源码

小满Vue3(第九章 computed计算属性-精讲) P11 - 24:12

p12

watch() --》 分页和搜索建议用watch

多个监听(一个一个监听简单点)

返回的newval、oldval也是数组,和前面对应!

深度监听

注意:

1、深层引用类型返回的新值和旧值一样,虽然可以监听到

例子1:

原因:

例子2:

例子3:

2、使用reactive不加deep也可以监听到深层!(doWatch源码里面判断是reactive就隐性开启了deep;如果是数组就进行递归,和deep一样,会对每个进行监听 --》 下方源码视频里讲的)

监听深度里面的某个属性

需要把其变成函数

immediate -> 立即执行一次

immediate默认为false,设置为true,默认会先走一次watch,oldval默认为undefined!

源码:

小满Vue3(第十章 watch侦听器 & 源码讲解) P12 - 06:53

p13

watchEffect() 高级监听器

直接把要监听的响应式变量放里面就行!(一开始就会执行一次,但是不会执行before,第二次执行才会执行before)

停止监听

watchEffect 会返回一个停止监听的函数!

flush

https://xiaoman.blog.csdn.net/article/details/122802130

控制watch执行的顺序,如:

下图ipt在setup时未加载,所以需要加上post,让组件更新后执行!!!

帮助调试

onTrigger

效果:

触发事件后

p14

生命周期

1、beforeCreate、create 在setup语法糖模式下,使用setup去代替!

2、onBeforeMount 及其之前都读取不到dom;onMount可以读取到!

3、onBeforeUpdate 获取的是更新之前的dom;onUpdated 获取的是更新之后的dom

代码:

结果:

注:

可以在更新之前做一些卸载操作,eg:卸载事件!

4、卸载

5、适用于调试 --》 就当普通生命周期使用就行

onRenderTracked收集依赖去触发的钩子,接收effect对象!

onRenderTriggered触发依赖更新去触发的钩子,接收effect对象!

https://juejin.cn/post/7209510210422685755

生命周期源码(不懂,后面看):

小满Vue3(第十二章 生命周期 & 源码讲解) P14 - 11:08

1、createHook(枚举),枚举的是生命周期的简称,将其传入组件自身的实例,并且使用了函数柯里化!

查看通过:getCurrentInstance 获取当前组件的实例!

2、wrappedHook,如果组件卸载直接return,不然停止依赖收集,避免重复收集(因为组件初始化时就已经收集过了)

3、injectHook 注册的钩子,在renderer.ts每个生命周期阶段都调用一下

4、componentUpdateFn

I、如果组件没挂载:先执行beforeMounted,然后render,然后patch将vnode挂载到容器中,然后就有了dom元素,然后就判断有没有 m--》mounted枚举,有就执行对应的生命函数

II、如果挂载了:就执行更新操作

小满Vue3(第十二章 生命周期 & 源码讲解) P14 - 14:28

5、后面有unmounted进行卸载

小满Vue3(第十二章 生命周期 & 源码讲解) P14 - 14:57

p15 重录了

1、bem规范 --》 前缀-块名__元素--描述

小满Vue3(第十三章 BEM架构 + layout布局) P15 - 00:40

https://zhuanlan.zhihu.com/p/72631379#

2、sass

https://www.sass.hk/docs/

scss 和 sass 区别,sass有自己的一套规则,而scss更加像css,所以推荐学习scss

a、变量

$xxx

*乘法 / 除法

b、if - else

这里并不是布尔值,只是字符串,用a、b也行,scss只有==没有===

c、循环

for……to 不包含最后一个数

for……through 包含最后一个数

直接用$xxx,其他地方用插值语句 #{$xxx}

d、each

数组不需要 []

index要靠索引函数 --》 index(当前数组,当前值) 获取 --》返回就是位置

e、混入 --》 函数 / 也可以简单一点,不要参数

I、定义

@mixin 名称($xxx:默认值,$yyy:

默认值){}

II、使用 --》 @include

f、嵌套 --》 & 代表当前元素

跳出嵌套 --》 @at-root

g、继承(类似混入,但是更加简单)

h、导入 @import ‘filepath’;

p16

父 -> 子

无法直接使用,要用变量接收

子 -> 父

子暴露给父(不推荐)--》 defineExpose

小满Vue3(第十四章 父子组件传参) P16 - 08:48

子:

父:

新版的elementui,里面form表单有使用!

小满Vue3(第十四章 父子组件传参) P16 - 10:56

p17

全局组件

整个系统中,出现频率很高的业务组件,在很多界面要用到

循环引入也可以(element plus):

局部组件

一个界面很多内容,不想写一起

递归组件

一个东西去复用,不确定里面有多少东西,例如:Tree、menu,递归生成的组件

组件调用自己,可以直接调用,名字要保持一致

不想一致,可以再建一个script标签,导出成你想用的名字!

插件用法 unplugin-vue-define-options(不重要)--》vue3.3直接支持defineOptions

小满Vue3(第十五章 全局组件,局部组件,递归组件) P17 - 10:11

p18

动态组件

节约性能(取消一些不用代理的对象)

小满Vue3(第十六章 动态组件 & 源码解析) P18 - 07:12

1、markRaw --》 会添加__skip__属性,让vue不去代理

2、shallowRef

vue2写法

小满Vue3(第十六章 动态组件 & 源码解析) P18 - 09:21

源码:

小满Vue3(第十六章 动态组件 & 源码解析) P18 - 10:36

p19

插槽slot

v-slot 语法糖 # ,取消使用 slot="name"

默认插槽用 #default 表示

vue2的this.$slots 可以获取传过来的全部slot

vue3使用 useSlots

作用域插槽:

动态插槽:

p20

顶层await --》 只能在setup语法糖中使用,vue封装好了

把整个组件变成异步组件!

小满Vue3(第十八章 异步组件&代码分包&suspense) P20 - 04:45

Suspense --》展示异步组件必须这个

注意:

有两个插槽,#default放加载成功的,#​fallback放加载中的

defineAsyncComponent

异步组件才用defineAsyncComponent,正常组件就正常引入!

函数风格

defineAsyncComponent 一般直接用 头函数+import函数模式 返回就行

对象风格

可以搞好几个不同组件(使用较少):

代码分包+性能优化

小满Vue3(第十八章 异步组件&代码分包&suspense) P20 - 09:11

打包的时候,异步引入[defineAsyncComponent]会产生分包[打包几个js文件],让首屏更快展示!

p21

teleport传送组件

主要是让子组件不受父组件样式影响!

可以通过to=“选择器”,传送到任意dom,然后通过disabled=“boolean”,控制to是否生效!

源码

小满Vue3(第十九章 Teleport传送组件) P21 - 04:39

p22

keep-alive

知道:include、exclude

max

缓存的最大数量 --》 自动剔除旧的不常用的

会添加两个生命周期:

onActivated、onDeactivated

源码

小满Vue3(第二十章 keep-alive缓存组件 & 源码解析) P22 - 07:59

1、返回了一个渲染函数,然后读取插槽的子节点,只能有一个,所以keep-alive渲染时里只能有一个子节点,可以放多个,但是要if-else

2、用Map、Set存缓存管理组件

3、pendingCacheKey在keep-alive render完之后赋值,所以第一次不会缓存,走了onMounted之后有值了,后面就不走了

4、如果组件上有动画,会优先处理动画

5、标记shapeflags(及上面说的patch flag) 为 512,让其不要销毁

p23、p24、p25

官网:https://cn.vuejs.org/guide/built-ins/transition.html#css-based-transitions

自定义动画class可以结合第三方库(animate.css \ gsap)使用!

p26

appear --》 首次动画加载

p27

transition-group 标签不显示在dom结构中

tag

让 transition-group下面再包裹一层标签

class名称、生命周期 --》 和transition都一样

p28

flip动画库

transition-group移动元素时的动画 --> 基于flip

名称使用move-class --》 移动特定的

p29

数字滚动 -> gsap

p30

provide()/inject() --》 vue通过原型链实现

provide(key, value)

inject(key)

provide传递的值可以被子组件修改!

不想被修改,provide加上readonly

源码

小满Vue3(第二十三章 依赖注入provide/inject & 源码解析) P30 - 06:15

1、先读取组件实例currentInstance,做了判断,provide函数模式只能在setup中使用!选项式只能用配置的方式!

2、读取当前组件实例的provide,然后读取父组件的provide,是否一致,一致就在父组件provide的基础上创建一个新对象,形成原型链,用下面的方法:

新奇的原型链

b直接输出没有,但是可以读取属性,因为b继承了a,原型链上!

3、inject 做了函数重载,也读取了组件实例,读不到就直接返回app的provide;读取到了就尝试去读父组件的provide

p31

兄弟组件传值

事件总线bus (现在都是mitt)

https://blog.csdn.net/langwang_100/article/details/119838102

手写发布订阅模式(不懂,后面看)

小满Vue3(第二十四章 兄弟组件传参&Bus) P31 - 04:42

简写就不用看ts类型限制!

class Bus {

let list;

construct(){

this.list = {}

}

emit(name,...args) {

let eventName=this.list[name]

eventName.forEach(fn => {

fn.apply(this,args)

})

}

on...

}

p32

mitt

初始化

ts:

普通js:

使用

监听多条换成 *

第一个参数:事件名称

第二个参数:传递参数

更多

off 方法

js 现在都是封装到utils下面:

p33 组件库会使用,vue3开发组合式api就行!

jsx / tsx(类似react,要换思想) 另一种写template的风格!

父组件:

xiaoman组件:

1、返回渲染函数

2、通过defineComponent 和 optionsApi (使用较少)

3、通过defineComponent 和 setup函数模式

4、一些指令的替换

v-show

jsx 要手动.value v-show={flag.value}

三元表达式代替v-if

小满Vue3(第二十五章 tsx & vite插件) P33 - 04:39

map代替v-for

小满Vue3(第二十五章 tsx & vite插件) P33 - 05:56

v-bind用{}代替

小满Vue3(第二十五章 tsx & vite插件) P33 - 06:41

props、emit

小满Vue3(第二十五章 tsx & vite插件) P33 - 07:09

1、

小满Vue3(第二十五章 tsx & vite插件) P33 - 08:43

2、emit要配合事件使用,不是@,直接是onXXX,要用函数柯里化(及箭头函数),将要使用的函数返回,不然会直接调用

3、emit在第二个参数中

插槽(不懂,后面看)

小满Vue3(第二十五章 tsx & vite插件) P33 - 10:51

v-model

小满Vue3(第二十五章 tsx & vite插件) P33 - 13:04

可以直接使用v-model

手写vite插件+babel(不懂,后面看)

小满Vue3(第二十五章 tsx & vite插件) P33 - 13:57

babel核心功能

p34

自动引入vue3组合式api引入的内容插件!

unplugin-auto-import

npm i -D unplugin-auto-import

注意:

不是界面中自动import引入,是配置引入,全局的,个人不太喜欢!

p35

v-model

对于input框时

对于组件时

什么是破坏性更新?

props是单向数据流,只允许父组件传输数据给子组件,不允许子组件修改父组件传递的数据!

props+emit是单向数据流,emit是告诉父组件要修改,由父组件修改 来改变子组件!

props是引用类型,会导致子组件修改,父组件也改的情况!(使用深拷贝解决)

多v-model

默认值传递是 v-model=“值”

其他值要用 v-model:xxxx = "值"

defineProps接收传递值默认是 modelValue

其他值要用xxx

emit事件默认是 'update:modelValue'

其他值要用 'update:xxx'

注:

默认值和其他值可以同时存在

自定义修饰符

内置:v-model.trim/lazy/number

默认:modelModifiers:{}

自定义:v-model:xxx.yyy

自定义:xxxModifiers:{

yyy:类型

}

小满Vue3(第二十六章组件( v-model & 源码解析) P35 - 07:48

源码--》使用了自定义指令

小满Vue3(第二十六章组件( v-model & 源码解析) P35 - 09:44

p36

directive-自定义指令(属于破坏性更新)

生命周期展示

小满Vue3(第二十七章 自定义指令) P36 - 02:26

名命 vXxxx

eg:

vMove = { }

使用

官网:https://cn.vuejs.org/guide/reusability/custom-directives.html#introduction

这些值每一个钩子函数都可以接收!通过 ...xxx

参数

第一个:el,当绑定指令的元素

第二个:传过来的参数都在这个里面

instance是当前组件实例

第三个:当前组件的虚拟dom(不常用)

第四个:上一个虚拟dom(不常用)

p37

简写

vMove = (el, bingding) => {

console.log(el, bingding)

}

结果

p39

图片懒加载

1、vite提供了批量引入图片

注意:

globEager废弃了

2、js的api介绍:

IntersectionObserver ((enr:array)=>{})

MDN:

https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver

enr属性:

p40

自定义hooks(暴露一个函数)和vue2的mixins类似 --》 都是抽离出来

但是mixins会有覆盖问题,因为生命周期顺序,mixins先于组件,那么组件的变量会覆盖mixins里的变量!

mixins里面的变量外面可以使用,但是找就不好找了

hook库:VueUse库

常用hook:

1、useAttrs --》 获取组件的全部传递的属性值

2、useSlots --》获取全部插槽(等同于vue2的this.$slot

手写hook --》 img转base64(不懂,后面看)

小满Vue3(第二十八章 自定义Hooks) P40 - 03:18

p41 自定义指令+hooks

1、hook结合指令 --》 监听dom宽高变化

小满Vue3( 自定义Hooks 综合案例) P41 - 03:55

注:

app.use 就是会去调用库里面的 install 方法,所以 install 的app参数是默认的,传入的是vue项目的app!

2、打包成库

小满Vue3( 自定义Hooks 综合案例) P41 - 07:50

3、发布npm --》 npm publish

小满Vue3( 自定义Hooks 综合案例) P41 - 10:58

p42

vue3定义全局函数和变量

vue2通过prototype定义

vue3没有prototype,通过createApp返回一个变量,然后通过变量追加全局函数和变量!

定义

调用

createApp源码(不懂,后面看)

小满Vue3(第二十九章 全局函数和变量) P42 - 04:45

p43

编写vue3插件 --》 loading插件

1、转化Vnode--》插件引入没法用,要转化

index.ts

必须有install方法!

2、render(挂载元素,挂载点)

3、暴露方法--》defineExpose

4、全局挂载

5、使用

手写app.use源码

小满Vue3(第三十章 自定义Vue插件 & 源码讲解) P43 - 12:06

app.use源码

小满Vue3(第三十章 自定义Vue插件 & 源码讲解) P43 - 16:15

1、返回app(当前实例),为了实现链式调用

2、use就是执行install

3、使用Set进行缓存,如果已经有plugin再次使用直接报错

https://www.jianshu.com/p/5485afe3cb35

p44

UI库

现在基本上都是:ts/js+setup语法糖,按需求去选择

p45

a、scoped

为什么不能修改ui组件里面的样式?

代码:

结果:

因为第二条,在末尾添加,但是第三条又是组件里面的组件会加到外层,所以选择不到!

b、样式穿透

:deep(类名) {}

只是把属性选择器挪动了位置!

c、源码

小满Vue3(第三十二章 样式穿透:deep() & 源码解析) P45 - 04:59

1、如果开启了scoped,就使用postcss插件去解析css,把css变成抽象语法树

2、vue写了一个postcss插件

3、Rule里面调用processRule,做了缓存用weakSet,里面接收的rule就是转成的AST

循环遍历,使用rewriteSelector重写选择器,及上面的把hash移到前面

p46

d、插槽选择器 --》 修改插槽里面的样式

:slotted(类名){}

注意:

这个是写在定义插槽的地方的

e、全局选择器 --》 一般就是不加scoped的style

:global(类名){}

f、动态css

1、

2、如果是对象

注意:

''

3、可以动态修改

g、css module --》 react/render/jsx使用较多

多个可以变成数组

自定义名字 --》 $style是默认名字

h、useCssModule --》 获取定义的css module(不常用)--》 react/render/jsx使用较多

p47

Tailwind css --》 不用学习(配合学习p51 unoCss)

p48

p49

Vue 更新

a、更新dom是异步的--》节省性能

注意:

watch只执行一次,dom也只变一次

b、数据更新是同步的

nextTick

1、回调函数方式 --》源码:把回调函数放到then中执行

2、async await 写法 --》 因为nextTick源码是返回的promise

注:

当操作dom的时候发现数据读取的是上次的,就需要使用nextTick

nextTick源码(不懂)

小满Vue3(第三十五章-nextTick & 源码解析) P49 - 05:56

1、vue3不支持ie,所以直接返回promise了;vue2会判断很多!

理解Tick

浏览器在一帧中做了什么事情?

1、requestidlecalback,就是空闲时间加载分包!

p50 跨平台

1、uniapp/ionic vue推荐ionic

2、react native 性能好

3、cordova 将原生html、css、js转成跨平台代码,如果有现成的项目有需求跨平台,就建议打包后传给他

4、weex 废弃

5、flutter 学习成本高,学dart

p51

h5适配

1、百分比相对于父元素,vw、vh相对于视口

2、px2viewport > pxtorem,因为pxtorem还要算,多大屏幕多大的字体比较合适(及引入flexible.js)

3、vite内置了postcss可以直接引用,postcss把css变成抽象语法树

手写插件(也可以直接用别人的)

小满Vue3(第三十六章 下 H5 适配 ) P51 - 08:10

全局字体大小

直接:root {}里面添加个变量就行,vue3支持style写变量!

怎么切换?

1、使用vueuse的useCssVar

2、使用

设置:document.documentElement.style.setProperty('--xxx',xxxx);

读取:

换成getProperty就行

p52

unoCss 原子化 --》集成了Tailwind、bootstrap等

见博客:

https://xiaoman.blog.csdn.net/article/details/125650172

p53

1、template 模版书写风格

2、tsx / jsx 编写风格

3、函数式组件 --》 h函数(可以直接从vue里引入) --》 原理:createVnode

a、优势

跳过了template模版的编译

模板编译过程:

h函数就可以跳过,直接到render函数

b、源码:

小满Vue3(第三十八章 函数式编程,h函数) P53 - 00:44

c、缺点

I、学习成本高,麻烦

II、vue3使用较少,因为优化了template模版的编译

d、实例 -》 适合封装很小的组件

小满Vue3(第三十八章 函数式编程,h函数) P53 - 03:10

p54 重录了

electron(不懂,可以学习,后面看)

创建项目步骤:

1、npm init vue

2、安装electron、electron-builder -D

建议直接使用electron创建,这个是从零搭建!

p55 重录了

vue3.2.25以上的新特性

需要开启配置才能使用 --》reactivityTransform:true

https://xiaoman.blog.csdn.net/article/details/126275355

现在应该可以直接用了

1、$ref() --》 ref() 的升级版,不需要 .value了

注:

a、watch监听不到 --》watch要监听响应式对象

解决:通过 $$() 把count变成响应式数据

b、$ref 最终还是会转化成ref加.value的形式,不过是vue自动帮我们加的

c、$() --》解构成响应式对象 --》 类似toRefs

$() 解构的也不用 .value

d、$computed、$shallowRef等,都是不需要写 .value

重录的 vue3.3 大部分是对ts的支持

defineProps

defineEmits

defineOptions

不能在里面定义已经有的编译宏(definexxx)的属性

defineSlots

小满Vue3(第四十章 Vue3.3编译宏) P55 - 10:32

编译宏源码

小满Vue3(第四十章 Vue3.3编译宏) P55 - 14:14

p56

vite的环境变量在import.meta.env里面!

1、自带的

2、自定义环境变量

a、在根目录下创建 .env.xxx,一般为development 和 production

里面配置 XXX = "xxxxx" 就行

b、配置package.json

注:

生产环境默认会读production,不需要配置;development也可以不配置了

c、vite.config.js 里面获取环境变量

这个配置文件里面是node运行环境,只能通过process.env获取环境变量,但是获取不到上面的两个文件的配置,得靠 loadEnv

参考我的vite笔记:

网页链接​

p57 webpack 构建 0 -》 1 重要

1、npm init

2、tsc --init

3、创建目录结构

4、安装webpack、webpack-cli(webpack3.0+必须安装这个)、启动dev的环境webpack-dev-server、安装html-webpack-plugin插件、安装vue

5、创建 + 配置webpack.config.js

注:

使用注解提供智能提示

注:

mode:'development' 表示打包后不压缩,压缩使用 production

6、package.json配置打包+运行命令

7、补充vue代码,HTML添加div#app,main.js引入和挂载vue,App.vue写入内容,打包报错 --》需要loader解析vue文件

安装 vue-loader@next、@vue/compliler-sfc

配置 webpack.config.js

8、发现dist里面的东西越打包越多 --》安装clean-webpack-plugin

配置 webpack.config.js

9、配置别名+自动识别后缀

10、引入css,发现报错--》需要loader解析css文件

安装css-loader、style-loader

配置 webpack.config.js

11、引入less

安装less、less-loader

配置 webpack.config.js

12、识别ts

安装typescript、ts-loader

配置 webpack.config.js,也是rules里面

13、美化webpack日志--》控制台输出的太乱

安装friendly-errors-webpack-plugin

配置 webpack.config.js,plugins里面

发现还是一堆,只是多了配置的,需要配置stats

结果:

注意:

这里打包也出现了,要用函数模式来,但是up没写

14、devserver配置 --》 常用配置框起来了

15、引入图片见

网页链接​ 的18、19

p58 vue3性能优化

FCP

Speed index

LCP

TTI

TBT

CLS 出现表示问题较大

分析打包后代码的体积

使用rollup的插件:rollup-plugin-visualizer

修改vite.config.js

vite打包优化

修改vite.config.js,build的配置(plugins同级)

vite插件做性能优化

1、pwa -》离线缓存

安装vite-plugin-pwa

修改vite.config.js

也是plugin注册,接收一个对象,很多配置要学,这里了解,见:

https://blog.csdn.net/qq1195566313/article/details/126811832

2、图片懒加载

安装vue3-lazy

使用:https://blog.csdn.net/qq_41161604/article/details/117660599

3、elementui的虚拟列表

4、vueuse

5、new Worker -》 不能操作dom

见:

https://blog.csdn.net/qq1195566313/article/details/126811832

p59

1、普通使用

样式隔离见:

https://blog.csdn.net/qq1195566313/article/details/127328300

使用

注:

可以复用

结果

2、template方式

四个生命周期

vue+web components

配置vite.config.js

跳过组件检测,识别为customElement,这个时候不能使用 .vue 为文件名,要使用 .ce.vue

注:

.ce.vue文件还是vue的写法,只不过会产生shadow隔离(不知道为什么要用这个??)

引入+挂载

p60

源码:(不懂,讲得不清楚)

小满Vue3(第四十六章 proxy跨域) P60 - 07:46

pinia相关

p61-p63

创建一个 store/index.js

修改store的5种方式

先看界面内容

方式一

直接操作 Test.current++

方式二

Test.$patch({current:xxx,name:'xxx'})

方式三 patch函数方式 --》推荐

Test.$patch((state)=>{})

方式四 只能修改整个对象,且必须都传(不常用)

Test.$state = {current:xxx,name:'xxx'}

方式五 通过action

定义action

修改

Test.setCurrent(567)

p64

storeToRefs 只会把 store 中的数据变成响应式,如果是 toRefs 就会把 store 里面的不需要变成响应式的都变成响应式!!!

storeToRefs在pinia里而不是vue

源码:

小满pinia(第四章解构store-源码解析) P64 - 02:45

1、用toRaw去把sotre转化成原始对象 --》 避免重复引用,因为下面要toRef

2、类似toRefs操作 --》遍历store,如果是ref对象或者reactive对象,将store[key]拷贝一份,然后用toRef包裹

p66 store的API

1、$reset

直接使用 Test.$reset() --》 恢复成默认值

2、$subscribe

$subscribe 相当于 pinia 的 watch !

3、$onAction

一调用action的方法就会监听

可传参

p67 手写pinia本地化插件

实战相关

p71 echarts5引入

import * as echarts from 'echarts'

不能直接

import echarts from 'echarts' 了

china.js 需要修改源码

删除

修改成这样

p73 通过json生成ts类型 --》 JSON2JS的vscode插件

小满实战篇可视化(第六章Map-数据) P73 - 01:57

p74 监听echarts点击事件

小满实战篇可视化(第七章-表格数据) P74 - 01:43

路由(router)相关

route 路由最好看:

网页链接​ 路由

p80 window原生两种路由方式

使用:

监听前进后退箭头的变化:

window.addEventListener('hashchange',(e)=>{})

监听前进后退箭头的变化:

window.addEventListener('popstate',(e)=>{})

使用:

一、

注意:

这个不会被popstate监听!直接使用vue提供的push方法!

二、

还有replace方法等

注意:

使用a标签跳转会刷新界面

p81 使用name跳转

p82

1、replace,不产生历史记录

2、前进历史用router.go(num),后退直接用router.back()/router.go(-1)

p83

params

小满Router(第四章-路由传参) P83 - 04:51

1、传的不能是对象或者数组

2、/:id,那params对象里面也要是id ;且只能传name

3、params值在内存里,刷新会丢失,所以用动态路由参数接收

小满Router(第四章-路由传参) P83 - 05:58

p84 嵌套路由

跳转的路径要加上父路由的前缀

p85 路由的多component模式(命名视图

使用router-view时使用name对应(default不用name)

使用场景:

1、两个tab页展示的内容形式不一样(重要

2、一个界面很多人开发又不想写组件

p86 重定向 redirect + 别名 alias

1、如果路由的配置path为 '',则表示默认路由

2、路由重定向 redirect,path有值但是又想默认展示

redirect 三种写法

I、字符串

II、对象

path 或者 name

III、回调函数

a、

b、

3、alias 取多个别名,不管访问什么别名,都可以跳转到对应路由

eg:

访问 / 或者 /rootx 都是访问的root.vue

p87 路由守卫 - 前置

注意:

不执行 next() 就不会跳转!

p88 路由守卫 - 后置

没有next参数

实例:

上方进度条

p89 路由元信息

就是路由配置时多加一个meta:{},配置自己想要的东西!

p90 路由过度动效

使用meta加上动画类名,然后通过vue自带的transition组件完成!

router-view支持插槽,可以解构出route+component

p91 滚动行为

创建router时,可以提供scrollBehavior方法

自动记录的position,就是切换到有滚动条的界面,自动滚到位置!

固定距离

支持异步

p92 动态添加路由

router使用addRoute({})增加路由

vite使用import时,不能使用@别名!

pm2相关

p93 了解pm2

为什么用pm2?

一个express项目里面监听很多接口,如果自己启动,要用很多cmd去一个一个node xxx.js

p94 使用pm2 --》 常用命令

1、使用pm2启动,进到文件夹,直接一个一个去pm2 start xxx.js,一个cmd就行,会显示成列表

2、查看运行结果

pm2 log

3、停止一个服务

pm2 stop id(列表里面的)

4、启动配置

pm2 start xxx.js --watch

--watch 就是监听 xxx.js 的变化,变化就自动重启!

5、node查看线程

os模块,使用os.cups()

6、使用 pm2 start xxx.js i 0~max 设置占用线程

7、使用 pm2 start xxx.js -n xxx 替换掉列表里面的name

8、pm2 monit 实时显示日志(p97讲)

9、pm2 restart all 重启所有项目(p107讲)

Linux相关

p96 Linux服务器安装node

https://blog.csdn.net/qq1195566313/article/details/123885302

配置环境变量:

1、pwd 获取 node bin 的位置安装的路径

2、前往根目录,cd etc,修改下面的etc/profile,此文件涉及系统的环境,即环境变量相关

3、vi profile,按一下 I键 进入编辑模式,在最后一行添加,export PATH=$PATH:/node-v14.19.1-linux-x64/bin

注意:

I、如果不是根目录,要加上xxx/node-v...

II、如果多个要加 :

4、执行 source profile 或者重启 linux

p97 服务器部署express

记住在防火墙放开端口!!!

小满服务端Linux(第五章-部署node接口) P97 - 03:57

p98 Linux文件属性

linux命令:使用 ls -l

p99 Linux权限

linux命令:ls -l 简写 ll

1、创建用户

adduser xxxx

2、设置密码

passwd xxxx

3、然后登录另一个账号,就能看到权限区别

4、root为其他用户增加权限,chmod 777 xxx

为什么是777?

Nginx相关

p100 认识nginx

https://xiaoman.blog.csdn.net/article/details/123958967

p101 安装nginx

linux命令:

直接查找某个文件/文件夹 whereis nginx

安装流程见 106

linux防火墙也会导致访问不到:

https://blog.csdn.net/qq1195566313/article/details/123965492

p102 nginx常用命令

linux命令:

查询某个应用下的进程 ps -ef | grep java/nginx

nginx 命令:

1、执行 nginx

2、停止 nginx -s stop / quit(这个更优雅,会等处理请求完成再关闭)

3、重载配置文件 nginx -s reload

p103 nginx配置文件

nginx命令:nginx -t 检查文件是否有语法错误,但是可以巧妙的用其找到位置!

https://blog.csdn.net/qq1195566313/article/details/124217010

nginx配置文件详解

1、全局块

a、user 一般就是nobody

2、events块

a、默认开启的不管

b、最大连接数越大越好,但是要注意cpu

3、http块

a、include、default_type一般也不用管,default_type就相当于请求没设置头,就默认按这个来

b、access_log ,http错误日志的位置

c、一般 keepalive_timeout 65; http1.1之后有优化,看一段时间内有没有相同地址的请求,这个就是相关设置!

3.1、server块

a、server_name 192.168.19.101;这里最好填IP地址而不是localhost

3.1.1、location块

p104 nginx反向代理 --》 解决跨域

sever -》 location -》 proxy_pass

注:

所有配置都要记得加分号!

p105 vue开启history刷新界面404

原因vue是单页应用,nginx就找不到路由对应的界面

解决办法:

try_files $url $url/ /index.html

注意:

1、$url 表示当前路径,不包括 ?后参数

2、后面表示将路径拼接到 index.html,重新定位到index.html

p106 nginx日志分析器 --》 go access(实时的)

下载流程

1、wget 下载地址

2、解压 tar -zxvf xxx

3、进入目录 cd xxx

4、执行 config 文件: ./configure

5、make 、 make install

6、查找安装位置 whereis xxx

注:

其他的安装也可以类比!!!

go access 使用:

1、找到nginx下的 logs/access.log

2、goaccess -f access.log(还是不行)

3、生成 html 模板 (更好)

3.1、去html目录下建一个html文件

3.2、回到logs下,执行

goaccess access.log -a -o ../html/xxx.html --real-time-html --log-format=COMBINED

具体介绍:

https://blog.csdn.net/qq1195566313/article/details/124546293

107 nginx负载均衡 --》 upstream

包含在http模块,和server同级!

这样配置的是均分压力,每个相同!

1、权重 weight

注:

I、= 左右不能有空格

II、权重大的,接收的请求就多

2、超时时间 fail_timeout

超时了就启用备用服务器,及backup标志的!

网络安全相关

p108 canvas指纹追踪技术

up文章地址:

网页链接​