• Vue3学习笔记


    1. Vue2与Vue3的区别

    1.1 v-ifv-for优先级

    2.x版本中 v-for > v-if

    3.x版本中 v-for < v-if

    1.2 v-for中的ref数组

    2.x版本中 会自动把ref填充内容

    3.x版本中 需要手动添加

    
    <ur>
        <li v-for='item in 5' :key='item' :ref="setItemRef">{{ item }}li>
    ul>
    
    <script>
        methods: {
            setItemRef(el){
                this.arr.push(el)
            }
        }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.3 $children

    2.x版本中 访问前实例的子组件

    3.x版本中 在3.x中,$children 已被移除,且不再支持。可以用以下方式所代替:

    设置: export default defineConfig({ plugins: [ AutoImport({ imports: ['vue', 'vue-router'] // 自动导入vue和vue-router相关函数 }) ] })

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.6 toRefs

    如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作:

    <script setup>
        import { reactive, toRefs } from 'vue'
    
        let obj = reactive({
            name: '张三',
            age: 20
        })
        let target = toRefs(obj)
        target.name.value = '李四'
        console.log(`姓名:${target.name},年龄:${target.age}`) //控制台  姓名:李四,年龄:20
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.7 computed

    接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。

    const count = ref(1)
    const plusOne = computed(() => count.value + 1)
    
    console.log(plusOne.value) // 2
    
    plusOne.value++ // 错误
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。

    const count = ref(1)
    const plusOne = computed({
      get: () => count.value + 1,
      set: val => {
        count.value = val - 1
      }
    })
    
    plusOne.value = 1
    console.log(count.value) // 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    let obj = reactive({
        name: '张三',
        age: '20',
        sex: computed(() => {
            return '男'
        })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.8 watch

    2.x版本中,watch的使用:

    watch: {
        obj: {
            handler(newVal, oldVal) {
                console.log(newVal, oldVal)
            },
            immediate: true // 当刷新页面时会立即执行一次handler函数
            deep: true // 深度侦听
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.x版本中,watch的使用:

    • 监控一个数据
    let msg = ref('Hello vue!')
    
    watch(msg, (newVal, oldVal) => {
        console.log(newVal, oldVal)
    },{
        immediate: true,
    })
    
    return {
        msg
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 监控多个数据(一起监控)
    let msg = ref('Hello vue!')
    let str= ref('Hello world!')
    let obj = reactive({
        name: '张三',
        hobby: ['篮球','游泳','射击']
    })
    
    watch([msg, str, ()=>obj.hobby], (newVal, oldVal) => {
        console.log(newVal, oldVal)
    },{
        immediate: true,
    })
    
    return {
        msg,str
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 监听对象中的对象
    let obj = reactive({
        name: '张三',
        hobby: ['篮球','游泳','射击']
    })
    
    watch(()=>obj.hobby, (newVal, oldVal) => {
        console.log(newVal, oldVal)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    watchEffect立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

    let msg = ref('Hello vue!')
    
    watchEffect(() => {
        console.log(msg.value)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.9 路由

    • Vue2.x与Vue3.x的区别
    Vue2.xVue3.x
    this.$routeuseRoute
    this.$routeruseRouter
    • 导航守卫

    • 动态路由

    2.10 组件

    2.10.1 父传子

    父组件:

    <template>
        <List :msg='msg' />
    template>
    
    <script setup>
        import List from '@/components/List'
        let msg = ref('父传子')
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    子组件:(defineProps自定义属性)

    <template>
        <div>这是子组件 ===> {{ msg }}div>
    template>
    
    <script setup>
        defineProps({
            msg:{
                type: String,
                default: ''
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2.10.2 子传父

    子组件:

    <template>
        <div>这是子组件 ===> {{ num }}div>
    template>
    
    <script setup>
    let num = ref(200)
    const emit = defineEmits(['getData'])
        const backData = () => {
        emits('getData', num)
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    父组件:

    <template>
        <List @getData='getData' />
    template>
    
    <script setup>
        import List from '@/components/List'
    
        const getData = val => {
            console.log(val)
        }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2.10.3 父子组件双向数据

    父组件:

    <template>
        <List v-model:num="num" />
    template>
    
    <script setup>
        import List from '@/components/List'
    
        const getData = val => {
            console.log(val)
        }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    子组件:

    <template>
        <div>这是子组件 ===> {{ num }}div>
        <button @click='btn'>按钮button>
    template>
    
    <script setup>
    const props = defineProps({
        num:{
            type: Number,
            default: 0
        }
    })
    const emit = defineEmits(['update:num'])
    const btn = ()=>{
        emit('update:num', 200)
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    2.10.4 兄弟传值

    父组件:

    <template>
        <A @fn='changeFn'/>
        <B/>
    template>
    
    <script>
    import 'A' from '@/components/A'
    import 'B' from '@/components/B'
    
    let str = ref('')
    let changeFn = val => {
        str.value = val.value
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    兄弟组件A(发送数据)

    <template>
        <h1>组件Ah1>
        <button @click='btn'>按钮button>
    template>
    
    <script setup>
    let str = ref('组件A中的数据')
    const emit = defineEmits(['fn'])
    const btn = () => {
        emit('fn', str)
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    兄弟组件B(接收数据)

    <template>
        <h1>组件B ===> {{ str }}h1>
        <button @click='btn'>按钮button>
    template>
    <script setup>
    const props = defineProps({
        str: {
        type: String,
        default: '123'
        }
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    兄弟组件使用mitt传值

    • 下载mitt

      npm i mitt -S

    • 配置文件(Bus.js)

      import mitt from 'mitt'
      
      const emmiter = mitt()
      
      export default emmiter
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 兄弟组件A(发送数据)

      <template>
          <h1>A组件h1>
          <button @click='btn'>按钮button>
      template>
      
      <script setup>
      import emitter from '@/utils/Bus.js'
      
      let str = ref('A组件传数据')
      const btn = () => {
          emitter.emit('fn', str)
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • 兄弟组件B(接收数据)

      <template>
          <h1>B组件 ===> {{ msg }}h1>
      template>
      
      <script setup>
      import emitter from '@/utils/Bus.js'
      
      let msg = ref('')
      onBeforeMount(() => {
          emitter.on('fn', e => {
              msg.value = e.value
          })
      })
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    3. 生命周期

    3.1 选项式API(与Vue2.x用法基本类似)

    3.2 setup组合式API

    选项式 APIHook inside setup
    beforeCreateNot needed*
    createdNot needed*
    beforeMountonBeforeMount
    mountedonMounted
    beforeUpdateonBeforeUpdate
    updatedonUpdated
    beforeUnmountonBeforeUnmount
    unmountedonUnmounted
    errorCapturedonErrorCaptured
    renderTrackedonRenderTracked
    renderTriggeredonRenderTriggered
    activatedonActivated
    deactivatedonDeactivated

    4. 插槽

    4.1 匿名插槽

    父组件:

    <template>
        <A>
            <template>这是xxxx数据template>
            <template>这是yyyy数据template>
        A>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    子组件:

    <template>
        <header>
            <div>头部div>
            <slot>slot>
        header>
        <footer>
            <div>底部div>
            <slot>slot>
        footer>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.2 具名插槽

    父组件:

    <template>
        <A>
            
            
            <template #xxx>这是xxxx数据template>
            <template #yyy>这是yyyy数据template>
        A>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    子组件:

    <template>
        <header>
            <div>头部div>
            <slot name='xxx'>slot>
        header>
        <footer>
            <div>底部div>
            <slot name='yyy'>slot>
        footer>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.3 作用域插槽

    父组件:

    <template>
        <A>
            
            <template #default='{data}'>
                {{ data.name }} --->{{ data.age }}
            template>
        A>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    子组件:

    <template>
       <div v-for='item in list' :key='item.id'>
           <slot :data='item'>slot>
       div>     
    template>
    
    <script setup>
    let list = ref({
        {id: 1, name: '张三', age: 20},
        {id: 2, name: '李四', age: 25},
        {id: 3, name: '王五', age: 20},
        {id: 4, name: '赵六', age: 18}
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.4 动态插槽

    通过数据进行切换

    <template>
       <template #[hw]>Hello world!template>
    template>
    
    <script setup>
        let hw = ref('hw')
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5. Teleport 【传送】

    • 传送给id选择器

    • 传递给class选择器

    • 传递给标签选择器

      传送之前,必须要声明出对应的选择器

    6. 动态组件

    
    <keep-alive>
        <component :is="currentTabComponent">component>
    keep-alive>
    
    • 1
    • 2
    • 3
    • 4

    7. 异步组件

    7.1 使用场景1

    组件按需引入:当用户访问到了组件再去加载该组件

    下载vueuse插件npm i @vueuse/core -S

    <template>
        <div ref='target'>
            <C v-if='targetIsVisible'>C>
        div>
    template>
    <script setup>
    import { useIntersectionObserver } from '@vueuse/core'
    
    const C = defineAsyncComponent(() =>
      import('@/components/C.vue')
    )
    
    const target = ref(null)
    const targetIsVisible = ref(false)
    
    const { stop } = useIntersectionObserver(
        target,
        ([{ isIntersecting }] => {
            if( isIntersecting ) {
                targetIsVisible.value = isIntersecting
            }
        })
    )
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7.2 使用场景2

    异步组件在默认情况下是可挂起的。这意味着如果它在父链中有一个 ,它将被视为该  的异步依赖。在这种情况下,加载状态将由  控制,组件自身的加载、错误、延迟和超时选项都将被忽略。通过在其选项中指定 suspensible: false,异步组件可以退出 Suspense 控制,并始终控制自己的加载状态

    <template>
        <Suspense>
            <template #default><A/>template>
            <template #fallback>加载中template>
        Suspense>
    template>
    <script setup>
    const A = defineAsyncComponent(() =>
      import('@/components/A.vue')
    )
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.3 打包时,分包处理

    npm run build打包完成后,异步组件有单独的js文件,是从主体js包中分离出来的。

    8. Mixin

    是什么?来分发Vue组件中的可复用功能

    8.1 setup写法

    mixin.js

    import { ref } from 'vue'
    
    export default function() {
        let num = ref(1)
        let fav = ref(false)
    
        let favBtn = () => {
            num.value += 1
            fav.value = true
            setTimeout(() => {
               fav.value = false
            },2000)
        }
        return {num, fav, favBtn}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    组件A:

    <template>
        <div>
            <h1>A组件h1>
            {{ num }}
            <button @click='favBtn'>{{ fav ? '收藏中...' : '收藏' }}button>
        div>
    template>
    
    <script setup>
    import mixin from '@/mixin/mixin.js'
    
    let {num, fav, favBtn} = mixin()
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    组件B:

    <template>
        <div>
            <h1>B组件h1>
            {{ num }}
            <button @click='favBtn'>{{ fav ? '收藏中...' : '收藏' }}button>
        div>
    template>
    
    <script setup>
    import mixin from '@/mixin/mixin.js'
    
    let {num, fav, favBtn} = mixin()
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    8.2 选项式API写法

    mixin.js

    export const fav = {
        data() {
           return {
               num: 1
            } 
        },
        methods: {
            favBtn(params) {
                this.num += params
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    A组件:

    <template>
        <div>
            <h1>A组件h1>
            {{ num }}
            <button @click='favBtn(2)'>按钮button>
        div>
    template>
    
    <script>
    import mixin from '@/mixin/mixin.js'
    
    export const fav = {
        data() {
           return {
               str: 'Hello vue!'
            } 
        },
        mixin: [fav]
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    B组件:

    <template>
        <div>
            <h1>B组件h1>
            {{ num }}
            <button @click='favBtn(1)'>按钮button>
        div>
    template>
    
    <script>
    import mixin from '@/mixin/mixin.js'
    
    export const fav = {
        data() {
           return {
               str: 'Hello vue!'
            } 
        },
        mixin: [fav]
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    9. provide和Inject 依赖、注入

    通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,可能会很麻烦。

    对于这种情况,我们可以使用一对 provide 和 inject。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

    Provide/inject scheme

    provide:

    <script setup>
        provide('changeNum', num)
    script>
    
    • 1
    • 2
    • 3

    inject:

    <template>
        <h1>{{num}}h1>
    template>
    <script setup>
        const num = inject('changeNum')
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    10. Vuex

    11. pinia

    pinia与Vuex的区别

    1. 支持选项式api和组合式api写法
    2. pinia没有mutations,只有:state、getters、actions
    3. pinia分模块不需要modules(之前vuex分模块需要modules)
    4. TypeScript支持很好
    5. 自动化代码拆分
    6. pinia体积更小(性能更好)
  • 相关阅读:
    VSCode搭建ESP32 ESP-IDF开发环境-Windows
    RabbitMQ学习笔记(一)(概述)
    uni.scanCode不支持h5扫码(用拍照或者获取相册识别二维码和条码)
    C++面试连环问-STL
    LeetCode in Python 10. Regular Expression Matching (正则表达式匹配)
    使用pypcd读取pcd时ValueError: field ‘__0000‘ occurs more than once错误
    第五篇 python 基本语法(一)
    Python学生公寓管理系统的设计与实现毕业设计源码181047
    S7net【C#】
    3D印刷电路板在线渲染查看工具
  • 原文地址:https://blog.csdn.net/qq_45953233/article/details/126077742