vue3更新的内容

个人笔记,还没总结完,不定期更新吧。

想看的可以去看小满老师的视频以及文档地址
b站小满老师
学习视频地址:https://space.bilibili.com/99210573
学习笔记地址:https://blog.csdn.net/qq1195566313?type=blog

一、双向绑定

Vue2.0版本是通过ES5的object.defineProperty

1、 不能监听数组的变化,除了push/pop/shift/unshift/splice/reverse/sort,其他都不行
2、.无法检测到对象属性的新增或删除
3、Object.defineProperty只能遍历对象属性直接修改(需要深拷贝进行修改)

Vue3.0版本是通过ES6的Proxy

1、 proxy有兼容性问题,不能用polyfill来兼容(polyfill主要抚平不同浏览器之间对js实现的差异)
2、直接监听对象而非属性
3、直接监听数组的变化
4、拦截的方式有很多种(有13种)
5、Proxy返回一个新对象,可以操作新对象达到目的

二、ref全家桶

1. ref:简单创建一个可响应的数据(源码本质上还是reactive)

ref本质也是reactive,ref(obj)等价于reactive({value: obj})

使用ref获取dom节点的属性

1.const V1= ref(null)
1.template中定义ref="V1"
2.onMounted中获取V1.vuele
3.V1 return出去;

代码如下:

<!-- videocontainer -->
<template>
    <div class="video-container">
      <video :src="props.src" ref="V1" style='top:0px' loop playsinline muted></video>
    </div>
</template>
 
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import {onMounted,ref} from 'vue';
export default {
  props:['src'],
  setup(props,context){
    const V1=ref(null);
    onMounted(()=>{
        console.log(V1.value);
    })
    return{
      props,V1,
    }
  },
}
</script>

2.isRef:是否为ref对象

3.shallowRef:创建一个跟踪自身 .value 变化的 ref,只有第一层为响应式,其值不会为响应式

只有第一层为响应式,triggerRef(),ref可改为响应式数据,页面更新

4. triggerRef:强制更新dom

5. customRef:自定义ref,可以控制数据的追踪跟触发更新

三、reactive全家桶

1. reactive

  • reactive 参数必须是对象 (json / arr),否则不具有响应式
  • 如果给 reactive 传递了其它对象(如Date对象),需要重新赋值

2. readonly(只读)

3. shallowReactive

只有第一层为响应式,所以只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图

四、to全家桶

1. roRef(创建一个响应式数据)

  • toRef的本质是引用关系,修改响应式数据会影响原始数据
  • toRef当数据发生改变是,界面不会自动更新
  • toRef接受两个参数,第一个是对象,第二个是对象的属性
  • toRef一次仅能设置一个数据

2. toRefs(创建多个响应式数据)

批量设置多个数据为响应式,并且和原始数据关联,不再更新视图
toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行

2.toRaw

转为普通对象,更新数据,不更新试图

五、computed

const $total = ref(0);
$total = computed(() => {
   return ...
})

六、watch

watch(监听的数据源(可以是ref,也可以是[ref1, ref2]),(oldVal,newVal)=> {},{ immediate:true, deep: true})

七、watchEffect高级监听器

import { watchEffect, ref } from 'vue'
let message = ref<string>('')
let message2 = ref<string>('')
 watchEffect((oninvalidate) => {
    oninvalidate(()=>{
       //触发监听之前会调用一个函数可以处理你的逻辑例如防抖
    })
},{
    flush:"post", 
    //有三个参数:pre组件更新前执行,sync强制效果始终同步触发,post组件更新后执行
    onTrigger () {
         debugger
        //调试 watchEffect
    }
})

八、vue2.x和3.x生命周期对比

在这里插入图片描述

Vue2.x的生命周期Vue3.x的生命周期
beforeCreatedelete
createddelete
beforeMountonbeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured

增加了两个新的调试钩子函数,两个钩子函数都接收一个DebuggerEvent:

  • onRenderTracked
  • onRenderTriggered
export default {
  onRenderTriggered(e) {
    debugger
    // 检查哪个依赖性导致组件重新渲染
  },
}

九、父子组件传值

1. 父传子

1.1父组件属性传,子组件defineProps,withDefaults接受

父组件:字符串不需要加:,其他的类型属性传
子组件:defineProps,withDefaults(props函数,对象默认值)

  • defineProps的写法
<template>
    <div class="menu">
        菜单区域 {{ title }}
        <div>{{ data }}</div>
    </div>
</template>
 
<script setup lang="ts">
defineProps<{
    title:string,
    data:number[]
}>()
</script>
  • withDefaults的写法
type Props = {
    title?: string,
    data?: number[]
}
withDefaults(defineProps<Props>(), {
    title: "张三",
    data: () => [1, 2, 3]
})
1.2 Provide / Inject

父组件

<template>
    <div class="App">
        <button>我是App</button>
        <A></A>
    </div>
</template>
    
<script setup lang='ts'>
import { provide, ref } from 'vue'
import A from './components/A.vue'
let flag = ref<number>(1)
provide('flag', flag)
</script>
    
<style>
.App {
    background: blue;
    color: #fff;
}
</style>

子组件

<template>
    <div style="background-color: green;">
        我是B
        <button @click="change">change falg</button>
        <div>{{ flag }}</div>
    </div>
</template>
    
<script setup lang='ts'>
import { inject, Ref, ref } from 'vue'
 
const flag = inject<Ref<number>>('flag', ref(1))
 
const change = () => {
    flag.value = 2
}
</script>
    
<style>
</style>

2.子传父

2.1 父组件通过事件获取子组件的值

子组件:defineEmits(‘事件名’), emit(‘事件名’, 要传递的数据)
父组件:@事件名= “getList” 点击callBack函数获取值

子组件

<template>
    <div class="menu">
        <button @click="clickTap">派发给父组件</button>
    </div>
</template>
 
<script setup lang="ts">
import { reactive } from 'vue'
const list = reactive<number[]>([4, 5, 6])
 
const emit = defineEmits(['on-click'])
const clickTap = () => {
    emit('on-click', list)
}
</script>

父组件

<template>
    <div class="layout">
        <Menu @on-click="getList"></Menu>
        <div class="layout-right">
            <Header></Header>
            <Content></Content>
        </div>
    </div>
</template>
 
<script setup lang="ts">
import Menu from './Menu/index.vue'
import Header from './Header/index.vue'
import Content from './Content/index.vue'
import { reactive } from 'vue';
 
const data = reactive<number[]>([1, 2, 3])
 
const getList = (list: number[]) => {
    console.log(list,'父组件接受子组件');
}
</script>
2.2 父组件直接获取子组件的值

父组件:通过ref获取
子组件: defineExport({ data }) 暴露
子组件

<template>


  <div>我是demo组件</div>

</template>


<script setup>

  import { ref, reactive } from 'vue'


  const isFlag = ref(false)

  const data = reactive({

    name: 'tom',

    age: 18

  })

  //把数据导出
  defineExpose({

    data,

    isFlag

  })

  </script>


父组件

<template>
    //给组件绑定ref,从ref上获取
  <Mode ref="refMode"></Mode>

</template>


<script setup>

  import { ref ,reactive,onMounted} from 'vue'

  import Mode from './view/mode.vue'
    
  //ref名称必须与绑定的名称相同
  let refMode = ref(null)
   
  //setup ## beforeCreate、create生命周期的集合这里是获取不到的
  console.log('refMode',refMode.value)

  onMounted(() => {
    //只能在在里面才能获取到完整的组件ref的信息
    console.log('refMode2',refMode.value)
    
    //通过解构获取
    const {data,isFlag} = refMode.value

    console.log('refMode3',data,isFlag)

  })


 

</script>


<style>

  #app {

    text-align: center;

  }

</style>

3. 兄弟组件传值

3.1 父组件充当桥梁
<template>
    <div>
        <A @on-click="getFalg"></A>
        <B :flag="Flag"></B>
    </div>
</template>
    
<script setup lang='ts'>
import A from './components/A.vue'
import B from './components/B.vue'
import { ref } from 'vue'
let Flag = ref<boolean>(false)
const getFalg = (flag: boolean) => {
   Flag.value = flag;
}
</script>
    
<style>
</style>
3.2 bus

写一个bus.ts

 
type BusClass<T> = {
    emit: (name: T) => void
    on: (name: T, callback: Function) => void
}
type BusParams = string | number | symbol 
type List = {
    [key: BusParams]: Array<Function>
}
class Bus<T extends BusParams> implements BusClass<T> {
    list: List
    constructor() {
        this.list = {}
    }
    emit(name: T, ...args: Array<any>) {
        let eventName: Array<Function> = this.list[name]
        eventName.forEach(ev => {
            ev.apply(this, args)
        })
    }
    on(name: T, callback: Function) {
        let fn: Array<Function> = this.list[name] || [];
        fn.push(callback)
        this.list[name] = fn
    }
}
 
export default new Bus<number>()

挂载到全局Vue config
或者单独的页面引入 import Bus from ‘bus.ts’
Bus.$ emit 触发,Bus.$ on监听

3.4 mitt

和vue2的bus差不多,略过

十、全局组件,局部组件,递归组件

10.1全局组件

和vue2的写法差不多,全局注册的时候如下


createApp(App).component('组件名',组件实例).mount('#app')

10.2局部组件

和vue2差不多局部引入

10.3 递归组件

暂时不想写,略过

十一、动态组件

动态切换

 <component :is="A"></component>
const tab = reactive<Com[]>([{
    name: "A组件",
    comName: markRaw(A)
}, {
    name: "B组件",
    comName: markRaw(B)
}])

十二、slot插槽

12.1匿名插槽

和vue2差不多,略过

12.2 具名插槽

和vue2差不多,略过

12.3作用于插槽

子组件属性传
父组件取值
子组件

    <div>
        <slot name="header"></slot>
        <div>
            <div v-for="item in 100">
                <slot :data="item"></slot>
            </div>
        </div>
 
        <slot name="footer"></slot>
    </div>

父组件

         <Dialog>
            <template #header>
                <div>1</div>
            </template>
            <template #default="{ data }">
                <div>{{ data }}</div>
            </template>
            <template #footer>
                <div>3</div>
            </template>
        </Dialog>

12.4动态插槽

        <Dialog>
            <template #[name]>
                <div>
                    23 (这里会变成header)
                </div>
            </template>
        </Dialog>
const name = ref('header')

十三、异步组件&代码分包&suspense

异步组件

<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>

代码分包

defineAsyncComponent + import 组件

suspense

     <Suspense>
            <template #default>
                <Dialog>
                    <template #default>
                        <延迟加载的组件/>
                    </template>
                </Dialog>
            </template>
 
            <template #fallback>
                <div>loading...</div>
            </template>
        </Suspense>

十四、新增Fragment、Teleport、Suspense组件(和react类似)

1.Fragment(不用加根节点)

vue2.0只能有一个根节点,会增加很多没有用的节点
vue3.0有虚拟的Fragment

2.Teleport

将子节点渲染到存在于父组件以外的 DOM 节点

Teleport其实就是React中的Portal。Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优良的计划。
一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 款式时,但你须要子组件可能在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。

  • 没有Teleport
    在这里插入图片描述
  • 有Teleport
    在这里插入图片描述
    Telepost的用法:
    在这里插入图片描述

3. Suspense

Suspense组件可以等待某个异步组件解析完成的前后的显示情况
使用方式
这个组件有两个具名插槽:
default - 默认的插槽。可以放置异步的组件
fallback - 可以放置组件未加载前的样式 比如 loading
用法:

 <Suspense>
        <template #default>
            <User />
        </template>
        <template #fallback>
            Loading...
        </template>
    </Suspense>

十五、keep-alive缓存

十六、transition动画组件

十七、transition-group过度列表

十八、TSX

十九、v-model

二十、directive自定义指令

二十一、自定义hooks

二十二、vue3定义全局函数和变量

二十三、编写vue3插件

二十四、pinia

二十五、Router

二十六、Filter

3.x 不再支持filter,可以用method 或者 computed来代替。

二十七、Better TypeScript support

使用 TypeScript 可以增加代码的可读性和可维护性

二十八、Composition API复用

2.0版本用的是mixins
3.0如下

<template>
    <div>X: {{ x }}</div>
    <div>Y: {{ y }}</div>
</template>

<script>
import { defineComponent, onMounted, onUnmounted, ref } from "vue";

const useMouseMove = () => {
    const x = ref(0);
    const y = ref(0);

    function move(e) {
        x.value = e.clientX;
        y.value = e.clientY;
    }

    onMounted(() => {
        window.addEventListener("mousemove", move);
    });

    onUnmounted(() => {
        window.removeEventListener("mousemove", move);
    });

    return { x, y };
};

export default defineComponent({
    setup() {
        const { x, y } = useMouseMove();

        return { x, y };
    }
});
</script>

下面暂时不更改

八、默认项目目录结构的不同

vue3移除了配置文件目录,config 和 build 文件夹,移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中,在 src 文件夹中新增了 views 文件夹,用于分类视图组件和公共组件

九、v-if和v-for的权重

2.0版本中是v-for的权重大于v-if
3.0版本中是v-if的权重大于v-for

十、安装vue3.x版本

1.全局安装create-vite-app

npm i -g create-vite-app
  • 创建项目目录
create-vite-app 项目名
  • 运行
cd 项目名
npm install
npm run dev
  • 升级2.x版本
vue add vue-next 
  • 3.x比2.x版本代码更精简,3.x引入了一个新的函数名createApp,会把容器挂载到它上面来。
//vue2.0
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
}).$mount('#app')

//vue3.0
import { createApp } from 'vue';
import App from './App.vue'
createApp(App).mount('#app')
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值