优秀的编程知识分享平台

网站首页 > 技术文章 正文

uniapp入门到进阶(必备知识扩展-1) - vue3你不知道的那些事

nanyue 2024-11-03 14:04:16 技术文章 4 ℃

一、组合式API

1、setup函数:组件中所有数据、方法、钩子函数等存放的容器,返回值有两个:

在beforeCreate之前调用,没有this

setup函数有两参数 setup(props,context)

props外部传入、内部声明接受的属性,值为对象;

context 包含

1、 attrs外部传入,props未声明,相当于this.$attrs

2、slots收到的插槽相当于this.$slots

3、emit 函数,相当于this.$emit

返回对象:则对象内的属性、方法可在模板直接使用;

若返回渲染模板函数,我们可以自定义渲染的内容

例如:

<script lang="ts">
    import { h } from 'vue'
    
    exportt default {
        name:'myApp',
        setup(props,context){
            //属性
            const name = '胖奶奶与胖小伙'
            
            //方法
            const Hi = (name:string):voild =>{
                console.log('Hi'+name)
            }
            
            //必须返回在模版才可以用,返回对象
            return {
                name,
                Hi
            }
            
            //返回渲染函数,需要我们引入 h
            return () => {
              return  h('span','我是渲染函数')
            }
        }
    }
    
</script>

2、ref,reactive的使用

<script lang="ts">
    //引入ref 、reactive
    import { ref,  reactive } from 'vue'
    
    exportt default {
        name:'myApp',
        setup(){
            //声明响应数据 name 
            //`基本类型数据`,不存在数据劫持
            const name = ref('胖奶奶与胖小伙')
            //修改 name  .value不可缺少 ,模板中使用不用 `.value`
            name.value = '我改变了'
            //获取 name
            console.log(name.value)
            
            //reactive,Proxy代理对象数据劫持实现响应式
            //1、对象类型数据   
            //**`处理一个响应式的对象数据` 注意无法处理基本类型数据**
            const msgList = reactive({
                name:'',
                job:'挖矿小伙'
            }) 
            //修改数据
            msgList.name = '胖奶奶与胖小伙'
            //获取数据job
            console.log(msgList.job)
            
            //2、数组数据
            const study = reactive(['语文','数学','体育'] )
            //修改 语文
            study[0] = '政治'
            //获取 数学
            console.log(study[1])
        }
    }
    
</script>

3、理解vue3响应式实现原理

在vue2中:存在的问题及解决方案,新增、删除数据或直接下标修改数组,页面无法更新

<script lang="ts">
    import vue from 'vue'
    
    exportt default {
        name:'myApp',
        data(){
            return {
                userMsg:{
                    name:'胖奶奶与胖小伙',
                    age:18
                }
            }
        },
        methods(){
            //在userMsg添加一个学历
            addEdu(){
                //该写发不生效
                this.userMsg.edu = '小学'
                
                //正确写法
                this.$set(this.userMsg,'edu','小学')
                //or
                vue.set(this.userMsg,'edu','小学')
                
            },
            delName(){
                //该写发不生效
                delete this.userMsg.name
                
                //正确写法
                this.$delete('this.userMsg','name')
                //or
                vue.set(this.userMsg,'name','胖奶奶与胖小伙')
            }
        }
       
    }
    
</script>

在vue3中响应式实现的原理,解决了Vue2存在的问题

<script lang="ts">
    //原始数据
    let userMsg = {
        name:'胖奶奶与胖小伙',
        age:18
    }
    
    //vue2响应式模拟,无法捕获添加,删除
    let uMsg = {}
    Object.defineProperty(uMsg,'name',{
        get(){
            return userMsg.name
        },
        set(){
            console.log('数据改变了')
            userMsg.name = ''
        }
    })
    
    //vue3响应式原理
    //映射userMsg,从而代理userMsg,Proxy可以捕获`增、删、改、查`
    
    //Proxy代理对象
    const uMsg = new Proxy(userMsg,{
        //获取
         get(target,propName){
             //可以实现响应式
           // return target[propName]
           
           //vue3底层实现通过反射对象 Reflect修改原对象属性
          return Reflect.get(target,propName)
        },
        
        //修改、添加
        set(target,propName,value){
            console.log('数据改变了')
              //可以实现响应式
            //userMsg.name = ''
            
             //vue3底层实现通过反射对象 Reflect修改原对象属性
            Reflect.set(target,propName,value)
        }
        //删除
        deleteProperty(target,propName){
           //可以实现响应式
           // return delete target[propName] //捕获删除
            
          //vue3底层实现通过反射对象 Reflect修改原对象属性
          return Reflect.deleteProperty(target,propName) //捕获删除
        },
    }) 
    
    
</script>

ref和reactive区别:

ref定义基本类型数据,也可定义对象数组类型数据,但内部会通过reactive转换为代理对象, ref通过Object.definePropertyget()set()实现响应式,操作数据需要.value,模版不需要,可直接使用 reactive只能定义对象、数组类型数据,通过Proxy数据劫持,并通过反射对象 Reflect 修改原对象属性实现响应式,读取操作数据不需要.value

4、计算属性、监听

<script lang="ts">
    //引入ref 、reactive、
    import { ref,  reactive, computed} from 'vue'
    
    exportt default {
        name:'myApp',
        //vue2中,开发中不建议vue2、vue3混用
        computed:{
            changeName(){
                return this.msgList.name + '520'
            }
        },
        setup(){ 
            const msgList = reactive({
                name:'',
                job:'挖矿小伙'
            }) 
            
            //vue3 中计算属性 —— 简写模式 不考虑修改
            msgList.changeName = computed(() => {
                return msgList.name + '520'
            })
            
            //完整模式,读写
            msgList.changeName = computed({
                //获取
                get(){
                  return msgList.name + '520'
                },
                
                //修改
                set(value){
                    msgList.name = value
                }
            })
            
            return {
                msgList
            }
        }
    }
    
</script>

wacth

<script lang="ts">
    import { ref,  reactive, computed, watch, watchEffect} from 'vue'
    
    exportt default {
        name:'myApp',
        
        //vue2中,开发中不建议vue2、vue3混用
        watch:{
             //简写
            total(newValue, oldValue){
                console.log(newValue)
            },
             //完整写法 
            total:{
                deep:true,
                immediate:true,
                handler(newValue, oldValue){
                    console.log(newValue)
                }
            }
        },
        setup(){ 
            const total =ref(0)
            const name = '小胖'
            const msgList = reactive({
                person:{
                    a{
                        name:'小胖'
                    }
                },
                name:'',
                job:'挖矿小伙'
            }) 
            
            /*****vue3中
            *
            *注意,可调用多个 watch**
            *注意,ref 基本数据类型不需要 `.value`
            *
            ******/
            
            //1、vue3 中监视 `ref` 数据
            watch(total,(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true })
            
            //2、vue3 中监视多个 `ref` 数据
            watch([total,name],(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true })
            
            //3、vue3 中监视多个 `reactive` 数据
             watch(msgList,(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true })
            
            //4、vue3 中监视 **多个 `reactive` 某个数据** 强制开启深度监视
            watch(() => msgList.name,(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true })
            
            //5、vue3 中监视 **多个 `reactive` 某些数据**
            watch([() => msgList.name,() => msgList.job],(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true })
            
            //6、vue3 中监视  `reactive` 特殊情况监视某个深度对象  需要开启深度监视
            watch([() => msgList.person,() => msgList.job],(newValue, oldValue) => {
                 console.log(newValue)
            },{ immediate:true ,deep:true})
            
           /******
           *
           * watchEffect 默认开启immediate
           * 可以分别监视需要的属性, 用谁监视谁
           * 有点类似 computed
           * 
           ******/
           watchEffect(() => {
               const a = total.value
               console.log(a )
           })
            
            return {
                total,
                name,
                msgList
            }
        }
    }
    
</script>

5、生命周期

??注意:vue3 提供了组合式API生命周期钩子

1、没有提供beforeCreate() created()组合API钩子,同等于 setup(); 2、更改了两个命名钩子beforeUnmount() 、 unmount();3、使用中需要引入

6、hook函数,作用封装组合式API,组件化

对功能化组件进行抽离,一般以use开头命名,例如在hook下创建 useDataTime.ts

// 时间戳转换
const dataTimes = (result):string => {
	const date = new Date(result);
	let y = date.getFullYear();
	let MM = date.getMonth() + 1;
	MM = MM < 10 ? ('0' + MM) : MM;
	let d = date.getDate();
	d = d < 10 ? ('0' + d) : d;
	let h = date.getHours();
	h = h < 10 ? ('0' + h) : h;
	let m = date.getMinutes();
	m = m < 10 ? ('0' + m) : m;
	let s = date.getSeconds();
	s = s < 10 ? ('0' + s) : s;
	return y + '-' + MM + '-' + d
}

export default dataTimes

7、其他组合API

toRetoRefs,把一个普通数据转换成响应式数据

<script lang="ts">
    import { ref,  reactive, toRe, toRefs} from 'vue'
    
    exportt default {
        name:'myApp',
        setup(){ 
            const msgList = reactive({
                name:'',
                age:20,
                job:'挖矿小伙'
            }) 
            
            return {
                msgList,//是响应式
                msgList.name,//不是响应式
                msgList.age,//不是响应式
                name:ref(msgList,'name'),//转换成ref响应式,但不改变原是数据 
                name:toRef(msgList,'name'),//toRef引用原数据
                ...toRefs(msgList)//toRefs把所有数据变成响应式
            }
        }
    }
    
</script>

shallowRefshallowReactive,浅层响应式,只考虑第一层数据;

readonlyshallowreadonly ,只读;

toRowmarkRow,原始的数据

<script lang="ts">
    import { ref,  reactive,shallowRef,shallowreactive, readonly, shallowReadonly} from 'vue'
    
    exportt default {
        name:'myApp',
        setup(){ 
        
            /******
            *
            * shallowreactive 只处理对象最外层响应式
            * shallowRef 只处理基本类型数据响应式,无法处理对象类型,一般数据只改变一次使用
            *
            ******/
            const msgList = reactive({
                name:'',
                age:20,
                job:{
                    salary:80000,
                    des:''
                },
                list:{}
            }) 
            
            const a = shallowRef(3)
            const a = shallowreactive({
                name:'',
                age:20,
                job:{
                    salary:80000,
                    des:''
                }
            })
            
            //把 `msgList` 响应式改为只读
            msgList = readonly(msgList)
            msgList = shallowReadonly(msgList) //浅层次
            
            //输出最原始数据
            const starts = () => {
                //数据中转,还原原数据,toRow只能处理reactive数据类型
                const a = toRow(msgList) //无法对a进行操作
                console.loog(a)
                
                //markRow 标为普通对象
                let list = {
                    x:1,
                    y:2
                }
                msgList.list = markRow(list)
                
            }
            
            return {
                msgList,
              
            }
        }
    }
    
</script>

customRef自定义响应式

/***
*
*  `customRef()` 预期接收一个工厂函数作为参数,这个工厂函数接受 `track` 和 `trigger`两个函数作为参数,
* 并返回一个带有 `get` 和 `set` 方法的对象。
*
* 一般来说,`track()` 应该在 `get()` 方法中调用,而 `trigger()` 应该在 `set()` 中调用。然而事
* 实上,你对何时调用、是否应该调用他们有完全的控制权。
*
*
***/
import { customRef } from 'vue'

export function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

组件中使用:

<template>
  <input v-model="text" />
</template>

<script setup lang="ts">
    import { useDebouncedRef } from './debouncedRef'
    const text = useDebouncedRef('hello')
</script>

组件件通讯,provideinject

<------- 父组件 ------->
<template>
 <h3>我是父组件</h3>
 <Child/>
</template>

//父组件 provide 提供
<script lang="ts">
   import { ref,  reactive, toRe, toRefs, provide} from 'vue'
   import 'Child' from './components/Child.vue'
   
   components:{
       Child
   },
   exportt default {
       name:'myApp',
       setup(){ 
           const msgList = reactive({
               name:'',
               age:20,
               job:'挖矿小伙'
           }) 
           provide('msgList',msgList)
           return {
              ..toRefs(msgList)
           }
       }
   }
   
</script>

<------- 子组件 ------->
<template>
 <h3>我是子组件</h3>
  <span></span>
</template>

//子组件 props 提供
<script lang="ts">
   import { ref,  reactive, toRe, toRefs,} from 'vue'
   
   components:{
       son
   },
   exportt default {
       name:'child',
       setup(props,ctx){ 
           console.log(props)
       }
   }
   
</script>

<------- 后代组件 ------->
//后代组件 inject 提供
<script lang="ts">
   import { ref,  reactive, toRe, toRefs, inject} from 'vue'
   
   components:{
       son
   },
   exportt default {
       name:'child',
       setup(){ 
           const msgList = reactive({
               name:'',
               age:20,
               job:'挖矿小伙'
           }) 
          let msgList =  inject('msgList')
           return {
              msgList
           }
       }
   }
   
</script>

判断是否是响应式数据,isRef()isReactive() isReadonly() isProxy()是否为真即可

Fragment虚拟跟组件、Teleport传送门组件、Suspense 异步组件

欢迎收藏、点赞!

最近发表
标签列表