Vue-搜索组件封装

组件代码:

 

<!-- 
    * @Descripttion:搜索组件-->
<template>
    <div class='YxkSearch'>
        <el-form :model="form" :ref="$attrs.formRef" v-bind="$attrs">
            <!-- 搜索项 -->
            <template>
                <el-form-item v-for="(item, index) in searchObj.list" :key="index" v-bind="formItemBind(item)">
                    <FormItem :form="form" :params="item" :selectOptions="selectOptions">
                        <template v-slot:[item.slots]="scope">
                            <slot :name="item.slots" :scope="{...scope, $index: index}"></slot>
                        </template>
                    </FormItem>
                </el-form-item>
            </template>
            <!-- 搜索按钮 -->
            <template>
                <el-form-item v-for="item in searchObj.button" :key="item.text">
                    <FormButton :params="item">
                        <template v-slot:text="scope">{{scope.text}}</template>
                    </FormButton>
                </el-form-item>
            </template>
        </el-form>
    </div>
</template>

<script>
    // 搜索项
    const FormItem = {
        props: {
            form: {
                type: Object
            },
            params: {
                type: Object
            },
            selectOptions: {
                type: Object
            }
        },
        render(createElement) {
            // 选择项
            const options = (params, list) => {
                // 属性
                let item = JSON.parse(JSON.stringify(list))
                let props = {
                    attrs: {
                        ...item
                    },
                    domProps: {},
                    children: []
                }
                // 属性key值
                if (params.keys) {
                    for (let key in params.keys) {
                        props.attrs[key] = item[params.keys[key]]
                        if (key == 'text') {
                            item.text = item[params.keys[key]]
                        }
                    }
                }
                this.selectOptions.list.map(list => {
                    if (params.ele == list.ele) props.ele = list.child // 选择项-元素
                    if (this.selectOptions.type.indexOf(params.ele) != -1) { // 选择项-文本
                        props.children = [{
                            ele: 'span',
                            domProps: {
                                innerHTML: item.text
                            }
                        }]
                    }
                })
                // 删除附属属性
                if (item.id !== undefined) delete props.attrs.id
                if (item.text) delete props.attrs.text
                return createNode(props)
            }
            const createNode = params => {
                // 元素ele
                let ele = params.ele
                // 属性
                let props = {
                    attrs: {
                        ...params.attrs
                    },
                    domProps: {
                        ...params.domProps
                    },
                    on: {}
                }
                // v-model绑定
                if (params.model && !params.slots) {
                    props.attrs.value = this.form[params.model]
                    props.on.input = e => {
                        this.$set(this.form, params.model, e)
                    }
                }
                // 子元素
                let childNodes = []
                if (params.children) {
                    childNodes = params.children.map(item => {
                        return createNode(item)
                    })
                }
                if (params.options) { // 子元素-选择项
                    childNodes = params.options.map(item => {
                        return options(params, item)
                    })
                }
                // 事件
                if (params.on) {
                    Object.assign(props.on, params.on)
                }
                // 插槽
                if (params.slots) {
                    childNodes.push(this.$scopedSlots[params.slots](params))
                }
                return createElement(ele, props, childNodes)
            }
            return createNode(this.params)
        },
    }
    // 按钮
    const FormButton = {
        props: {
            params: {
                type: Object
            }
        },
        render(createElement) {
            const createNode = params => {
                // ele 元素
                let ele = params.ele || 'el-button'
                // 属性
                let attrs = JSON.parse(JSON.stringify(params))
                if (attrs.text) delete attrs.text
                if (attrs.click) delete attrs.click
                let props = {
                    attrs: {
                        ...attrs
                    },
                    on: {}
                }
                // 事件
                if (params.click) {
                    props.on.click = params.click
                }
                // 子元素
                let childNodes = []
                childNodes.push(this.$scopedSlots.text(params))
                return createElement(ele, props, childNodes)
            }
            return createNode(this.params)
        },
    }

    export default {
        name: 'YxkSearch',
        componentName: 'YxkSearch',
        props: {
            searchObj: {
                type: Object,
                default: () => {
                    return {}
                }
            },
            form: {
                type: Object
            }
        },
        components: {
            FormItem,
            FormButton
        },
        data() {
            return {
                selectOptions: {}
            }
        },
        methods: {
            // v-bind
            formItemBind(obj) {
                if (!this.searchObj.button) { // 默认搜索按钮
                    this.searchObj.button = [{
                        text: '搜索',
                        plain: true,
                        type: 'primary',
                        icon: 'el-icon-search',
                        click: () => this.searchSet()
                    }]
                }
                return this.deleteParams(obj, ['ele', 'model', 'attrs', 'on', 'domProps', 'options', 'keys', 'slots'])
            },
            // delete params
            deleteParams(obj, arr) {
                let params = JSON.parse(JSON.stringify(obj))
                arr.forEach(item => {
                    delete params[item]
                })
                return params
            },
            // 默认搜索事件
            searchSet() {
                this.$emit('searchSet')
            },
            // 键盘回车事件
            onKeyDown() {
                if (this.searchObj.isKeyDown !== false) {
                    document.onkeydown = () => {
                        const key = window.event.keyCode;
                        if (key == 13) this.$emit('searchSet')
                    }
                }
            },
            // 初始化
            initialSet() {
                this.selectOptions = {
                    list: [{ // 选择项
                        ele: 'el-radio-group',
                        child: 'el-radio'
                    }, {
                        ele: 'el-checkbox-group',
                        child: 'el-checkbox'
                    }, {
                        ele: 'el-select',
                        child: 'el-option'
                    }],
                    type: ['el-radio-group', 'el-checkbox-group'] // 特殊处理选择项
                }
            }
        },
        computed: {},
        watch: {},
        created() {
            this.initialSet()
            this.onKeyDown()
        },
        mounted() {}
    }
</script>

<style lang='scss'>
    .YxkSearch {
        padding: 20px;
        background: #fff;

        .el-form {
            display: flex;
            flex-wrap: wrap;
            align-items: flex-end;

            .el-form-item {
                margin: 0 22px 22px 0;

                .el-checkbox-group {
                    display: flex;
                    width: 100%;
                }

                .el-input,
                .el-select {
                    width: 100%;
                }
            }
        }
    }
</style>

 

示例:

 

 

参数说明:

YxkSearch

 

 

searchObj.list

 

 

searchObj.button

 

 

slot

 

 

事件 Events

 

 

 

posted @ 2023-11-17 16:27  忙着可爱呀~  阅读(137)  评论(0)    收藏  举报