how to encapsulate second time of ui components
For example we have follow code, with one UI component MyInput
// App.vue
<template>
<div>
<MyInput></MyInput>
</div>
</template>
<script setup>
import MyInput from './components/MyInput.vue'
</script>
// MyInput.vue
<template>
<di class="my-input">
<el-input></el-input>
</div>
</template>
<style scoped>
.my-input {
transition: 0.3s;
}
.my-input:hover,
.my-input:focus-within {
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.45))
}
</style>
1. binding the attributes
For example, <MyInput v-model="data" placeholder="Address"></MyInput>
, input
has lots of attributes, therefore we don't want to add everything into props
;
In vue, we can use v-bind="$attrs"
// App.vue
<template>
<div>
<MyInput v-model="data" placeholder="Address"></MyInput>
</div>
</template>
<script setup>
import {ref} from "vue"
import MyInput from './components/MyInput.vue'
const data = ref("")
</script>
// MyInput.vue
<template>
<di class="my-input">
<el-input v-bind="$attrs"></el-input>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
.my-input {
transition: 0.3s;
}
.my-input:hover,
.my-input:focus-within {
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.45))
}
</style>
2. Slots
input
elements has many slots as well. We need to support slots as well in our component.
// App.vue
<template>
<div>
<MyInput>
<template #prepend>
<el-select placeholder="Select" style="width: 115px">
<el-option label="Restaurant" value="1" />
<el-option label="Order No." value="2" />
<el-option label="Tel" value="3" />
</el-select>
</template>
<template #append>
<el-button :icon="Search" />
</template>
</MyInput>
</div>
</template>
// MyInput.vue
<template>
<div class="my-input">
<el-input v-bind="$attrs">
<template v-for="(value, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}"></slot>
</template>
</el-input>
</div>
</template>
<script>
export default {
}
</script>
3. ref
From MyInput
, you might want to add a ref
which should be able to access the methods of input
element.
We can expose those mothods in MyInput
component.
// App.vue
<template>
<div>
<MyInput ref="inputRef" v-model="data" placeholder="Address">
<template #prepend>
<el-select placeholder="Select" style="width: 115px">
<el-option label="Restaurant" value="1" />
<el-option label="Order No." value="2" />
<el-option label="Tel" value="3" />
</el-select>
</template>
<template #append>
<el-button :icon="Search" />
</template>
</MyInput>
</div>
</template>
<script setup>
import {ref, onMounted} from "vue"
import MyInput from './components/MyInput.vue'
import {Search} from "@element-plus/icons-vue"
const data = ref("")
const inputRef = ref(null)
onMounted(() => {
console.log(inputRef.value)
inputRef.focus()
})
</script>
// MyInput.vue
<template>
<div class="my-input">
<el-input ref="inp" v-bind="$attrs">
<template v-for="(value, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}"></slot>
</template>
</el-input>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.$refs.inp)
const entries = Object.entries(this.$refs.inp)
for (const [key, value] of entries) {
this[key] = value
}
}
}
</script>