vue 百宝箱2

55 阅读3分钟

优雅的处理 ts 类型问题

app.vue
 <MyButton type="primary" @click="onclick" :msg="msg"></MyButton>


 -MyButton.vue-
 
 <script>
 
  import {ButtonProps} from 'element-plus'
  // element-plus 导出了prop类型!!!
  
  step1:const props = defineProps<ButtonProps>(), 
  //定义了props 就可以替换 v-bind="$attrs"  为 props, 这样
 </script>
 <div>
 
  <el-button :loading="loading" @click="onclick" v-bind="props"></el-button>
 
 </div>
 
 step2:  step1后,:loading="loading" 会有类型提示错误, 这是因为在 element-plus 中,buttonprops中存在 loading这个属性
 
所以需要通过Omit,剔除某些属性!!!  const props = defineProps<Omit<ButtonProps, 'loading'>>(), 剔除掉这个loading类

step3: element-plus 中 的props 类型中存在很多声明成必传的,但是其实不是必须的  
借助 Partial 这个工具类型,将属性变为可选!!! const props = defineProps<Partial<Omit<ButtonProps, 'loading'>>>()

step4: 需要注意属性继承的问题, 这里在 <MyButton type="primary" @click="onclick" :msg="msg"></MyButton> 定义的click ,由于vue的属性继承默认是TRUE, 所以el-button 外的div 为root 节点是会继承到这个click 事件的,所以会触发两次click  div一次  el-button 一次。 这里需要在 

defineOptions({
 inheritAttrs:false // 关闭属性继承
})

vue3 中 $attrs

    import {useAttr} from 'vue'
    $attr === const attr = useAttr()
    表示 获取除了 props 之外的所有的属性。
    
    比如: 
    <MyButton type="primary" @click="onclick" :msg="msg"></MyButton>
    
    -MyButton.vue-
    《script》
    import {useAttr} from 'vue'
    const attrs = useAttr()
    const onClick = async() => {
     const data = await attrs?.onClick()
    }
    
    </script>
    <el-button @click="onclick" v-bind="$attrs"></el-button>
    //这样 三个 属性就都自动绑到组件内部了。
    
    但是如果  const props = defineProps<{type:string}>()
    定义了一个props,里面有type:string, 那么 type="primary" 就不会被$attr 所捕获,而是到props里了
    

二次封装组件,如何统一一次性暴露子组件所有的方法.

在子组件defineExpose中返回一个代理对象,get对应key的时候,返回对应的方法。


-myInput.vue-
<js
    const inputRef = ref()
    
    defineExpose(new Proxy(
    {},
    {
     get(target,key) {
         return inputRef.value?[key]
     }
     //但是注意,这里必须要判断一下是否key在ref对象上
     has(target,key) {
         return key in inputRef.value
     }
    }
    ))
>

<template>
 <div>hello world</div>
 <el-input  ref="elInput" v-bind="$attrs">
     <template v-for="(_, slot) in $slots" :key="slot" #[slot]="slotProps">
         <slot :name="slot" v-bind="slotProps"></slot>
         // 对于插槽的处理!!!
     </template>
 </el-input>
</template>

-app.vue-
<js
    const myInputRef = ref()
    
    const onClick = function() {
        myInputRef.value.focus()
    }
>

<template>
<button @click="onClick">点击获取input焦点</button>
 <myInput v-model="msg"  ref="myInput">
    <template #prepend>
        <el-button></el-button>
    </template>
    <template #append>
        <el-button></el-button>
     </template>
 </myInput>
</template>


vue动画

@vueuse/motion vue 动画库 也是vueuse的一部分!! npm i @vueuse/motion !!! 不是在vueuse/core 里的

ref 和 reactive 的区别

官方建议直接ref一把梭哈。

reactive 只能声明 数组或者对象 reactive([]|{}) ref 可以处理基础类型 reactive(0) 会报错

而且 对于 const list = reative([1,2,3])

当赋值 list = await getData() // 返回 [4,5,6] 视图不会变化,因为reactive声明的变量地址的改变【reactive([1,2,3]) 与 [3,4,5] 地址不同 】是无法被vue 监听到。

但是ref ,赋值变化是可以被vue监听到的

vue2 vue3 中如何监听子组件的生命周期!!

[【对于一些需要等到子组件加载完毕后才发起的操作都可以在这个方式里面调用!!!】]

 -app.vue-
 
const childMounted = () => {}
 
 <Child @childMounted="childMounted">
 // 关于这种暴露自定义方法去监听子组件声明周期对于自己写的组件是可以的,但是对于比如来自第三方组件库的组件就是不行的。
 </child>
 
 vue2中监听第三方组件库的方法!!!
 《comp1  @hook:mounted="childMounted"》</comp1>
 
  vue3中监听第三方组件库的方法!!!
 《comp1  @vue:mounted="childMounted"》</comp1>
 
 -child.vue-
 const emit = defineEmits(['childMounted'])
 onMounted(() => {
 emit('childMounted')
 })
 
 
 

#vue 异步更新以及nextTick原理

都知道vue 视图更新是异步的,这是因为可能会存在多个视图更新任务同时触发,

h 函数的使用

h 函数返回一个vnode


cons comp = h('div',{}, 'hello world')

<template>
    <component :is="comp"></component>
</template>



image.png

image.png

改为: const comp = () => h('div',{style:{},

onClick() { // 这样传递点击事件!! }}}, msg.value)

setTimeout(() => {msg.value = 'changed!!!'},2000) 这时候两秒钟后 视图就会改变, 这是因为comp 不是直接返回一个vnode ,而是返回一个函数, 函数执行的时候才返回一个vnode, 此时函数是在组件渲染的时候执行的,这时候调用函数的环境就是一个effect, 所以就会收集到依赖并且通知更新!!!

这种用法就是函数式组件的雏形,还可以传参数!!!

image.png

image.png

image.png

image.png

也可以直接渲染一个组件 import helloWorld from '@/compoments/helloWorld.vue'

const comp = () => { return h(helloWrold) }

image.png

image.png

监听自定义事件:

image.png

image.png

如何传递props?

image.png

接收props

image.png

接收嵌套的作用域插槽?

image.png

image.png

h 函数的使用场景

场景1: ant design vue 中 a-table的 列的自定义

image.png

更好的方式!!!

image.png

image.png

场景2, 点击一个按钮,弹框操作

常规的方式都是: <a-button @click="handleClick" />

handleClick() { open.value = true }

另一种的方式,借助于h函数:

image.png

场景3 组件的二次封装!

app.vue

image.png

child.vue 里面渲染helloworld

这路需要将传递给child的插槽传递给helloworld。

image.png image.png image.png