第一章
1.mvvm架构

2.回顾vue2对比vue3
区别:
vue2选项式api
vue3组合式api
关于这两个的区别,你可以不准确的理解为,选项式api更贴近原生标准html文件结构;
而组合式api就像在html标签中写css;当然做了优化,没准升华了
就这么个东西

3.vue3新特性

重写双向绑定
vue2和vue3都是用的js原生方法;
vue3重写了双向绑定,改为用ES6的新特性(好像是)proxy

vue2部分源码



vue3部分源码
由于vue2的劫持和特别是重写数组;对于数组(好像是劫持数组)不太友好(具体可能是劫持不到);所以用proxy重写了

vue3 tree shaking

vue3 composition api
setup语法糖
不懂😎
第二章
nvm 与node
nvm : node的版本管理工具,坑:空,中文路径,node版本重新添加或者卸载重安
nodejs部分架构


nodejs的源码好像包含些c

处理最总要的好像是io流,毕竟是对并发处理好的机制(优点)


第三章
关于vite项目的目录
待补充
vscode中vue2和vue3插件
智能提示书写语法会冲突,2,3要禁用一个
npm run dev 是如何执行的
在vite中查看packag.json
会发现软连接bin制定到...
之后这个文件做了linux系统,window系统的一些相关配置(🤔。。。)
第四章vue3模版语法
vue3书写风格

支持模版语法
api调用

三元表达

vue指令用法
v-html模板(也许是自定义模板???🤔)
。。。
v-if
关于v-if是如何在false下消失的,打开浏览器开发者模式查看,发现被注释掉了
为什么说v-show比v-if性能高
v-show在被设置为false后,是添加了display:none
看起来切换css要比注释性能高(look🤨)
@click点击

冒泡😅
v-bind绑定
简写:":"
、
常用动态绑定css,style,class,id....
v-model绑定
一般绑定的表单元素;
ref属性觉定v-model是否是响应式
v-for遍历数组
.....

v-once;v-memo
v-once,只渲染一次


v-memo如果跟空数组,效果和v-once是一致的
v-memo节省一小部分性能;大概是一万条数据,5s左右;不执行则跳过

第五章虚拟DOM和diff算法
介绍虚拟DOM
AST语法数:这个东西在ES6转ES5的插件babel;ts转js中会进行ast转换
根据满哥说的,我的理解是vue3在用js去描述DOM对象;这个描述和操作不一样(js操作dom)
正在上传…重新上传取消
为什么不直接操作dom:
原因:dom的属性太多,影响性能

我看是说这一次描述dom,会全部描述进去,影响性能

最长递增子序列

不清楚,刷算法再说喽

第六章ref全家桶
全家...
内置的特殊 Attributes | Vue.js

手写防抖

在 Vue 中,我们可以很轻松的实现防抖和节流。防抖指令 v-debounce:
html <input @input="doSomething" v-debounce="500">
该指令会在用户输入完后 500ms 后再执行 doSomething 方法。我们也可以手工实现一个防抖的 debounce 方法:
js
export default {
  methods: {
    debounce(func, wait) {
      let timeout
      return function() {
        let context = this
        let args = arguments
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          func.apply(context, args)
        }, wait)
      }
    }
  }
} 
然后在组件中这样使用:
html <input @input="debounce(doSomething, 500)">
节流指令 v-throttle:
html <input @scroll="doSomething" v-throttle="500">
该指令会在用户连续滚动 500ms 内只执行 doSomething 方法一次。我们也可以手工实现 throttle 方法:
js
export default {
  methods: {
    throttle(func, wait) {
      let timeout, context, args  
      return function() {
        context = this
        args = arguments   
        if (!timeout) {    
          timeout = setTimeout(() => {
            timeout = null
            func.apply(context, args)
          }, wait)
        }
      }
    }
  }
} 
然后在组件中这样使用:
html <input @scroll="throttle(doSomething, 500)">
所以,在 Vue 中使用防抖和节流非常简单,既可以使用内置的 v-debounce 和 v-throttle 指令,也可以手动实现 debounce 和 throttle 方法,在组件方法中使用。希望这个介绍能帮助你在 Vue 项目中熟练使用防抖和节流技术。它们能有效优化组件的性能,提高用户体验,是 Vue 开发中很重要的技能。
第七章reactive全家桶
reactive
不可以绑定普通的数据类型这样是不允许 会给我们报错
绑定普通的数据类型 我们可以 使用昨天讲到ref
reactive基础用法
import{reactive} form"vue"
let person=reactive({
name:'xiaoman'
})
person.name="daman" 
数组异步赋值问题
脱离响应式的情况
let person =reactive<number[]>([])
setTimeout(()=>{
person=[1,2,3]
console.log(person);
},1000)
 
解决方案1
使用push
import{reactive} from "vue"
let person =reactive<number[]>([])
setTimeout(()=>{
person.push(...arr)
console.log(person);
},1000) 
方案2
包裹一层对象
ts
type Person={
list?:Array<number>
}
let person =reactive<Person>({
list:[]
})
setTimeout(()=>{
const arr =[1,2,3]
person.list=arr;
console.log(person);
},1000) 
 
这创建了一个反应式变量person的类型Person,初始值为list的空数组。
1秒后,这个定时器函数会运行。它创建一个数组arr,[1, 2, 3]并将其分配给person.list。 由于person是反应性的,此赋值将触发反应性更新。 然后我们记录person并看到更新的值,列表[1, 2, 3]。总之,这显示了一个基本示例,创建一个反应性变量person并更新其中一个属性list,从而触发反应性更新,更新控制台日志。所以这个示例展示了在TypeScript中使用响应式变量的基础知识。定义一个带可选属性的接口,创建一个该接口的响应式变量,然后更新该变量的属性,触发更新并查看更新后的值。
readonly
拷贝一份proxy对象将其设置为只读??
import {reactive,readonly} from 'vue'
const person = reactive{{count:1}}
const copy = readonly(person)
//person.count++
copy.count++
 
shallowReactive
hallowReactive 是 Vue 中实现浅响应式 (shallow reactive) 的一个函数。正常来说,在 Vue 中数据对象的所有属性都是深度响应式的,也就是说,如果对象的嵌套属性改变了,此对象的 reactive 响应式代理也会产生变更通知。有时候我们只希望外层属性是响应式的,而不希望内部嵌套对象是响应式的。这种情况下可以使用 shallowReactive 函数来创建一个浅层响应式代理:
只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图
<template>
<div>
{{state}}
<button @click="change1">
test1
</button>
<button @click="change1">
test2
</button>
</div>
</template>
<script setup lang="ts">
import{sahwllowReactive}from "vue"
const obj={
    a:1,
    first:{
        b:2,
        second:{
        c:3
        }
     }
}
const state = shallowReactive(obj)
function change1(){
state.a=7
}
function change2(){
state.first.b=8
state.first.second.c=9
consloe.log(state);
}
</script> 
第八章to系列全家桶
toRef toRefs toRaw
 
<template>
<div>0
    <button @click="change">按</button>
    {{state}}
</div>
<template>
<script setup lang="ts">
import{reactive,toRef}from "vue"
const obj={
foo:1,
bar:1
}
const state = toRef(obj,'bar')
//bar 转化为响应式对象??
const change=()=>{
state.value++
console.log(obj,state);
}
<script>
 
 
如果原始对象是响应式的是会更新视图并且改变数据的
在这段代码中,bar 实际上并没有转化为响应式对象。这段代码做了以下几件事:1. 定义了一个普通对象 obj,包含 foo 和 bar 属性2. 使用 toRef 从 obj 中获取 bar 属性的响应式引用,赋值给 state3. 定义一个 change 方法,对 state.value 进行更改4. 在模板中使用 state 显示数据,并绑定 click 事件到 change 方法当我们点击按钮,调用 change 方法时,会发生以下事情:1. state.value 由于是响应式的,所以更改它会触发界面更新2. 但是 obj 中的 bar 属性本身并不是响应式的,所以 obj 对象自己并不会更新3. 我们在 change 方法中 console.log 了 obj 和 state,会看到:- obj 中的 bar 仍然是更改前的值 - state.value 已经更新了所以,关键的是要理解:- toRef 创建的响应式引用 state 与原对象 obj 中的属性 bar 实际上不是同一个东西 - state 是响应式的,会触发更新 - obj 的 bar 属性本身仍然是普通属性,不具有响应性只有当我们 wieder 给 obj.bar 赋值时,state.value 才会跟着更新,因为它 internally 还是连接着 obj.bar 的。所以 toRef 并没有使 obj 中的 bar 属性本身变为响应式的,它只是创建了一个 bar 属性的响应式引用 state 而已。
toRefs
可以帮我们批量创建ref对象主要是方便我们解构使用
import {reactive,toRefs} from "vue"
const obj = reactive({
foo:1,
bar:1
})
let {foo,bar} = toRefs(obj)
foo.value++
console.log(foo,bar); 
toRaw
将响应式对象转化为普通对象
import {reactive,toRaw} from "vue"
const obj=reactive({
    foo:1,
    bar:1
})
const state= toRaw(obj)
//响应式对象转换为普通对象
cosnt change()=>{
    console.log(obj,state);
} 
源码解析toRef
如果是ref 对象直接返回 否则 调用 ObjectRefImpl 创建一个类ref 对象
export function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K,
  defaultValue?: T[K]
): ToRef<T[K]> {
  const val = object[key]
  return isRef(val)
    ? val
    : (new ObjectRefImpl(object, key, defaultValue) as any)
 
- T 表示对象的类型,它必须是 object 或 object 的子类型 - K 表示对象的键的类型,它必须是 T 的键之一 - defaultValue 是一个可选参数,表示默认值这个函数的作用是:- 检查 object[key] 是否已经是一个 ref 对象,如果是的话直接返回 - 否则创建一个 ObjectRefImpl 的实例,它实现了 ToRef 接口,并将 object、key 和 defaultValue 作为构造函数的参数 - 最后将这个 ObjectRefImpl 的实例作为 ToRef<T[K]> 的实例返回所以简而言之,这个函数的作用是:如果对象的某个键还没有关联的 ref,那么为其创建一个 ref,从而让使用者可以对这个键所指向的属性进行响应式监测。这个函数看起来像是 Vue3 中创建 ref 的工具函数,它通过检查属性是否已经是 ref 来防止重复创建 ref 的情况出现。
类ref 对象只是做了值的改变 并未处理 收集依赖 和 触发依赖的过程 所以 普通对象无法更新视图
class ObjectRefImpl<T extends object, K extends keyof T> {
  public readonly __v_isRef = true
 
  constructor(
    private readonly _object: T,
    private readonly _key: K,
    private readonly _defaultValue?: T[K]
  ) {}
 
  get value() {
    const val = this._object[this._key]
    return val === undefined ? (this._defaultValue as T[K]) : val
  }
 
  set value(newVal) {
    this._object[this._key] = newVal
  }
} 
源码解析toRefs
其实就是把reactive 对象的每一个属性都变成了ref 对象循环 调用了toRef
export type ToRefs<T = any> = {
  [K in keyof T]: ToRef<T[K]>
}
export function toRefs<T extends object>(object: T): ToRefs<T> {
  if (__DEV__ && !isProxy(object)) {
    console.warn(`toRefs() expects a reactive object but received a plain one.`)
  }
  const ret: any = isArray(object) ? new Array(object.length) : {}
  for (const key in object) {
    ret[key] = toRef(object, key)
  }
  return ret
} 
toRaw 源码解析
通过 ReactiveFlags 枚举值 取出 proxy 对象的 原始对象
export const enum ReactiveFlags {
  SKIP = '__v_skip',
  IS_REACTIVE = '__v_isReactive',
  IS_READONLY = '__v_isReadonly',
  IS_SHALLOW = '__v_isShallow',
  RAW = '__v_raw'
}
 
export function toRaw<T>(observed: T): T {
  const raw = observed && (observed as Target)[ReactiveFlags.RAW]
  return raw ? toRaw(raw) : observed
} 
枚举是什么
枚举(Enum)是 TypeScript 中的一种类型,它定义了一些带名字的常量。枚举可以使代码更易读和理解。TypeScript 支持数字的和基于字符串的枚举。数字枚举:
ts
enum Direction {
  Up = 1,
  Down,
  Left,
  Right 
} 
这里,Up 的初始值为 1,其他成员会从 2 开始自动增长。我们可以这样使用枚举成员:
ts let dir = Direction.Up;
字符串枚举:
ts
enum Message {
  Success = "SUCCESS",
  Fail = "FAIL"
} 
我们也可以不给枚举成员赋初始值,此时第 0 个成员默认为 0,之后的成员值会自动增 1:
ts
enum Response {
  No = 0,
  Yes 
}
let res: Response = Response.Yes;  // res = 1 
枚举也可以拥有常数成员和计算成员:
ts
enum Color {
  Red,     // 常数成员,默认值为 0
  Green,   // 1
  Blue,    // 2 
  Cyan = Blue + 2  // 计算成员,值为 4
} 
枚举类型也可以被混入到接口和类型别名中:
ts
interface WindowState {
  state: WindowStates  // 枚举类型
}
type WindowStates = "open" | "closed" | "minimized";  // 字符串类型 
总之,枚举是 TypeScript 中一种简单但非常实用的类型,它常用于属性值域的定义和替换魔法字符串。
魔法字符串
魔法字符串指的是在代码中嵌入的不可读的字符串值。例如:
ts
function handleMessage(message) {
  if (message === "SUCCESS") {
    // ...
  } else if (message === "FAIL") {
    // ...
  }
} 
这里的 "SUCCESS" 和 "FAIL" 就是魔法字符串。魔法字符串有以下几个问题:1. 不易理解:魔法字符串的意思不容易被人理解,阅读者无法从字符串值本身推导出其语义。2. 容易拼写错误:由于字符串值不具有自我描述性,所以很容易拼写错误却不被检测出来。3. 难以改变:如果需要改变字符串值,需要改变所有使用该字符串的地方,这很容易遗漏某些位置而导致 bug。4. 没有类型安全:字符串可以随意修改,而它所代表的语义却没有变化,这会导致类型错误。所以,通常我们会使用枚举来替换魔法字符串:
ts
enum Message {
  Success = "SUCCESS",
  Fail = "FAIL" 
}
function handleMessage(message: Message) {
  if (message === Message.Success) {
    // ...
  } else if (message === Message.Fail) {
    // ...
  }
} 
这样可以解决上述所有的问题:1. 易于理解:枚举成员的名字本身就具有语义。
-  
没有拼写错误:我们操作的都是枚举成员,拼写是由编译器保证的。
 -  
易于改变:如果需要改变枚举的值,只需要改变枚举定义处的内容,使用处不需要修改。
 -  
类型安全:枚举是一个类型,用它来约束变量可以实现类型安全。所以,通过使用枚举,我们彻底消除了魔法字符串,使代码更健壮、易于理解和维护。
 
第九章 computed计算属性
computed用法
计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值。
1.函数形式
import{ computed,reactive,ref} from"vue"
let m =computed<string>(()=>{
return `$`+ price.value
})
price.value=500 
2.对象形式
<template>
 <div>{{mul}}</div>
 <div @click="mul=100">
 click
 </div>
</template>
<script setup lang="ts">
import {computed,ref} from "vue"
let price = ref<number| string>(1)//$0
let mul=computed({
get:()=>{
return price.value
},
set:(value)=>{
price.value='set'+value
}
})
</script> 
computed购物车案例
<template> <div> <input placeholder="请输入名称" v-model="keyWord" type="text"> <table style="margin-top:10px;" width="500" cellspacing="0" cellpadding="0" border> <thead> <tr> <th>物品</th> <th>单价</th> <th>数量</th> <th>总价</th> <th>操作</th> </tr> </thead> <tbody> <tr v-for="(item, index) in searchData"> <td align="center">{{ item.name }}</td> <td align="center">{{ item.price }}</td> <td align="center"> <button @click="item.num > 1 ? item.num-- : null">-</button> <input v-model="item.num" type="number"> <button @click="item.num < 99 ? item.num++ : null">+</button> </td> <td align="center">{{ item.price * item.num }}</td> <td align="center"> <button @click="del(index)">删除</button> </td> </tr> </tbody> <tfoot> <tr> <td colspan="5" align="right"> <span>总价:{{ total }}</span> </td> </tr> </tfoot>
</table> </div>
</template>
<script setup lang='ts'> import { reactive, ref,computed } from 'vue' let keyWord = ref<string>('') interface Data { name: string, price: number, num: number } const data = reactive<Data[]>([ { name: "小满的绿帽子", price: 100, num: 1, }, { name: "小满的红衣服", price: 200, num: 1, }, { name: "小满的黑袜子", price: 300, num: 1, } ])
let searchData = computed(()=>{ return data.filter(item => item.name.includes(keyWord.value)) })
let total = computed(() => { return data.reduce((prev: number, next: Data) => { return prev + next.num * next.price }, 0) })
const del = (index: number) => { data.splice(index, 1) }
</script>
<style scoped lang='less'></style>
手写源码 effect.ts
interface Options { scheduler?: Function } let activeEffect; export const effect = (fn: Function,options:Options) => { const _effect = function () { activeEffect = _effect; let res= fn() return res } _effect.options = options _effect() return _effect }
const targetMap = new WeakMap() export const track = (target, key) => { let depsMap = targetMap.get(target) if (!depsMap) { depsMap = new Map() targetMap.set(target, depsMap) } let deps = depsMap.get(key) if (!deps) { deps = new Set() depsMap.set(key, deps) }
deps.add(activeEffect) }
export const trigger = (target, key) => { const depsMap = targetMap.get(target) const deps = depsMap.get(key) deps.forEach(effect => { if(effect?.options?.scheduler){ effect?.options?.scheduler?.() }else{ effect() } }) } reactive.ts
import { track, trigger } from './effect'
const isObject = (target) => target != null && typeof target == 'object'
export const reactive = <T extends object>(target: T) => { return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver) as object
        track(target, key)
 
        if (isObject(res)) {
            return reactive(res)
        }
 
        return res
    },
    set(target, key, value, receiver) {
        const res = Reflect.set(target, key, value, receiver)
 
        trigger(target, key)
 
        return res
    }
}) 
}
computed.ts
import { effect } from './effect'
export const computed = (getter: Function) => { let value = effect(getter, { scheduler: () => { _dirty = true } }) let catchValue let _dirty = true class ComputedRefImpl { get value() { if (dirty) { catchValue = _value() _dirty = false; } return catchValue } }
return new ComputedRefImpl()
} html
<script type="module">
    import {computed} from './computed.js'
    import {reactive} from './reactive.js'
    window.a = reactive({name: 'a', age: 18})
    window.b = computed(() => {
        console.log('重新计算')
        return a.age + 10
    })
    
</script> 
</body> </html>
第九章代码选自大佬小满博客,资料参考小满博客和视频
小满zs的博客_CSDN博客-Vue3,typeScript,nest-js领域博主



















