Vue 3 + Element Plus 重写 Select 组件
·
以下是使用 Vue 3 和 Element Plus 重新编写的 Select 组件:
完整重写代码
vue
<template>
<el-select
:style="{ width: width }"
v-model="currentValue"
:placeholder="placeholder"
:loading="loading"
filterable
remote
:remote-method="handleRemoteQuery"
:clearable="clearable"
:disabled="disabled"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item.id"
:label="item.name"
:value="item.id"
:disabled="item.disabled"
>
<span style="float: left">{{ item.name }}</span>
</el-option>
</el-select>
</template>
<script setup>
import { ref, watch, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
const props = defineProps({
modelValue: {
type: [String, Number, Array],
required: true
},
width: {
type: String,
default: '60%'
},
clearable: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
orderId: {
type: [String, Number],
default: null
},
placeholder: {
type: String,
default: '请选择'
},
// 函数属性使用 camelCase 命名
fnChange: {
type: Function,
default: null
},
handleSelectItem: {
type: Function,
default: null
}
})
const emit = defineEmits(['update:modelValue', 'change'])
const loading = ref(false)
const options = ref([])
const disOpts = ref([])
// 使用 computed 处理双向绑定
const currentValue = computed({
get: () => props.modelValue,
set: (value) => {
emit('update:modelValue', value)
}
})
// 监听 orderId 变化
watch(() => props.orderId, (newVal, oldVal) => {
if (newVal !== oldVal) {
currentValue.value = ''
refresh()
}
}, { deep: true })
// 远程搜索方法
const handleRemoteQuery = (query) => {
if (query) {
refresh(query)
} else {
refresh()
}
}
// 选择变化处理
const handleChange = (val) => {
emit('change', val)
if (props.fnChange) {
props.fnChange(val)
}
if (props.handleSelectItem) {
props.handleSelectItem(val)
}
}
// 刷新数据方法
const refresh = async (param = '') => {
loading.value = true
try {
// 这里替换为您的实际 API 调用
const response = await $api.dongxw.OrderLine.query({
orderBys: 'id|desc',
param: {
orderId: props.orderId,
isDeleted: false,
customerOrderCode: param || undefined
}
})
options.value = response.data || []
} catch (error) {
console.error('获取数据失败:', error)
ElMessage.error('获取数据失败')
options.value = []
} finally {
loading.value = false
}
}
// 提供外部调用的方法
const remoteQryOrder = (param) => {
refresh(param)
}
// 组件挂载时初始化
onMounted(() => {
refresh()
})
// 暴露方法给父组件
defineExpose({
remoteQryOrder,
refresh
})
</script>
<style scoped>
/* 组件样式 */
:deep(.el-select-dropdown__item span) {
width: 140px;
text-align: left;
display: inline-block;
}
</style>
使用示例
在父组件中使用
vue
<template>
<div class="container">
<h3>订单选择器</h3>
<OrderSelect
v-model="selectedOrder"
:order-id="currentOrderId"
:width="'300px'"
:clearable="true"
placeholder="请选择订单行"
@change="handleOrderChange"
/>
<div style="margin-top: 20px;">
<p>当前选中的值: {{ selectedOrder }}</p>
<el-button @click="changeOrderId">切换订单ID</el-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import OrderSelect from '@/components/OrderSelect.vue'
const selectedOrder = ref('')
const currentOrderId = ref(123)
const handleOrderChange = (value) => {
console.log('订单选择变化:', value)
// 这里可以处理选择变化后的逻辑
}
const changeOrderId = () => {
currentOrderId.value = currentOrderId.value === 123 ? 456 : 123
}
</script>
<style scoped>
.container {
padding: 20px;
}
</style>
主要改进点
1. 使用 Composition API
-
使用
setup语法糖 -
使用
ref和computed响应式变量 -
使用
watch监听属性变化
2. 正确的双向绑定
-
使用
modelValue和update:modelValue替代 Vue 2 的value和input -
使用
computed处理双向绑定
3. 更好的 TypeScript 支持
-
明确的类型定义
-
更好的类型推断
4. 现代化的样式处理
-
使用
scoped样式 -
使用
:deep()选择器处理子组件样式
5. 错误处理
-
添加了 try-catch 错误处理
-
使用 ElMessage 显示错误信息
6. 组件暴露方法
-
使用
defineExpose暴露方法给父组件 -
保持与原有组件相同的接口
注意事项
-
API 调用:确保
$api.dongxw.OrderLine.query在 Vue 3 中正确配置 -
样式穿透:使用
:deep()替代 Vue 2 的/deep/或::v-deep -
事件处理:使用新的 emits 系统替代 Vue 2 的
$emit -
生命周期:使用
onMounted替代created
这样的重写保持了原有功能,同时利用了 Vue 3 的新特性,代码更加简洁和现代化。
更多推荐



所有评论(0)