vue 基于组件的二次封装

2023-06-27  本文已影响0人  wxw_威

组件不满足需求,要对当前组件再次封装,会遇到以下一些问题:

1、原组件的Attributes怎么处理原组件属性可以通过透传

$attrs,获取父组件的属性

<el-input ref="childInputRef" v-bind="$attrs"></el-input>
2、原组件的插槽怎么设置

通过$slots获取当前组件所有的插槽对象,通过遍历添加到原组件插槽
子组件:searchInput.vue

<el-input ref="childInputRef" v-bind="$attrs">
  <template v-for="(value, name) in $slots" #[name]>
    <slot :name="name"></slot>
  </template>
</el-input>

父组件

<SearchInput >
      <template #append">
        <el-button>Search</el-button>
      </template>
    </SearchInput>

效果:


1687939543818.png

具名作用域插槽
子组件:searchInput.vue

<el-input ref="childInputRef" v-bind="$attrs">
  <template v-for="(value, name) in $slots" #[name]>
    <slot :name="name" :slotData="slotData">></slot>
  </template>
</el-input>
...
....
const slotData = reactive({
  msg: 'aaaa'
})

父组件

<SearchInput>
  <template #append="{slotData}">
    {{ slotData.msg }}
   <el-button>Search</el-button>
  </template>
</SearchInput>

效果:


1687939766543.png

3、原组件的ref方法调用
将原组件的提供的方法加入到当前组件中
子组件:searchInput.vue

<el-input ref="childInputRef" v-bind="$attrs"></el-input>
<script setup lang="ts">
import { useAttrs, ref, onMounted, reactive, useSlots } from 'vue'

const childInputRef = ref()
const options = reactive<{[key: string]: any}>({})

const slotData = reactive({
  msg: 'aaaa'
})

onMounted(() => {
  const entries = Object.entries(childInputRef?.value)
  console.log('entries:', entries)
  for (const [key, value] of entries) {
    if (!value || typeof value !== 'function') {
      continue
    }
    options[key] = value
  }
})

父组件:

<template>
  <div>
    <SearchInput
      ref="searchInput" 
  >
    </SearchInput>
    <el-button @click="changeFocus">Focus</el-button>
  </div>
</template>

<script setup lang="ts"> 
const searchInput = ref()
function changeFocus() {
  searchInput.value.focus()
}
</script>
完整代码:

子组件:searchInput.vue

<template>
  <div>
    <el-input ref="childInputRef" v-bind="$attrs">
      <template v-for="(value, name) in slots" #[name]>
        <slot :name="name" :slotData="slotData"></slot>
      </template>
    </el-input>
  </div>
</template>

<script setup lang="ts">
import { useAttrs, ref, onMounted, reactive, useSlots } from 'vue'

// const attrs = useAttrs()
const slots = useSlots()
const childInputRef = ref()
const options = reactive<{[key: string]: any}>({})

const slotData = reactive({
  msg: 'aaaa'
})

onMounted(() => {
  const entries = Object.entries(childInputRef?.value)
  console.log('entries:', entries)
  for (const [key, value] of entries) {
    if (!value || typeof value !== 'function') {
      continue
    }
    options[key] = value
  }
})

defineExpose(options)
</script>

父组件:index.vue

<template>
  <div>
    <SearchInput
      ref="searchInput" 
      v-model="searchForm.keyword"  
      placeholder="请输入"
      active-value
      show-password
      clearable
      @change="handleChange">
      <template #append="{slotData}">
        {{ slotData.msg }}
        <el-button>Search</el-button>
      </template>
    </SearchInput>
    <el-button @click="changeFocus">Focus</el-button>
  </div>
</template>

<script setup lang="ts"> 
import SearchInput from './views/layout/components/searchInput.vue'
import { onMounted, reactive, ref, toRef, toRefs, getCurrentInstance } from 'vue';

const searchInput = ref()
const searchForm = reactive({
  keyword: ''
})

function changeFocus() {
  console.log('keyword:', searchForm.keyword)
  searchInput.value.focus()
}
function handleChange(v: string) {
  console.log('input:', v)
}

</script>

<style lang="scss" scoped>
</style>
上一篇下一篇

猜你喜欢

热点阅读