美文网首页前端开发那些事儿
【Vue3+Vite+TS】9.0 改造项目整体结构

【Vue3+Vite+TS】9.0 改造项目整体结构

作者: bobokaka | 来源:发表于2021-12-31 18:14 被阅读0次

    优化菜单

    这里存在一个bug,修复如下:
    修改src\components\baseline\menu\src\index.vue

    <template>
        <div>
            <el-menu
                class="el-menu-vertical-demo"
                :default-active="defaultActive"
                :router="router"
                v-bind="$attrs"
            >
                <template v-for="(item, index) in data" :key="index">
                    <!-- 一级无二级菜单的菜单栏 -->
                    <el-menu-item
                        v-if="!item.children || !item.children.length"
                        :index="item.index"
                    >
                        <component v-if="item.icon" :is="item.icon"></component>
                        <span>{{ item.name }}</span>
                    </el-menu-item>
                    <el-sub-menu
                        v-if="item.children && item.children.length"
                        :index="item.index"
                    >
                        <template #title>
                            <component v-if="item.icon" :is="item.icon"></component>
                            <span>{{ item.name }}</span>
                        </template>
                        <!-- 二级菜单栏 -->
                        <el-menu-item
                            v-for="(item2, index2) in item.children"
                            :index="item2.index"
                        >
                            <component
                                v-if="item2.icon"
                                :is="item2.icon"
                            ></component>
                            <span>{{ item2.name }}</span>
                        </el-menu-item>
                    </el-sub-menu>
                </template>
            </el-menu>
        </div>
    </template>
    <script lang="ts" setup>
    import { PropType } from 'vue'
    import { MenuItem } from './types'
    
    const props = defineProps({
        //说明:
        data: {
            required: true,
            type: Array as PropType<MenuItem[]>,
        },
        // 默认选中的菜单
        defaultActive: {
            type: String,
            default: '',
        },
        //是否是路由模式 router,
        //是否启用 vue-router 模式
        //启用该模式会在激活导航时以 index 作为 path 进行路由跳转
        router: {
            type: Boolean,
            default: false,
        },
    })
    // console.log('data:', props.data)
    </script>
    <style lang="scss" scoped>
    .el-menu-vertical-demo:not(.el-menu--collapse) {
        width: 2rem;
        min-height: 4rem;
    }
    svg {
        margin-right: 0.04rem;
    }
    </style>
    
    

    修改src\components\baseline\container\src\navAside\index.vue

    <template>
        <div>
            <bs-menu
               :collapse="collapse"
                :data="data"
                router
                :default-active="$route.path"
            ></bs-menu>
        </div>
    </template>
    <script lang="ts" setup>
    import { reactive, ref } from 'vue'
    let props = defineProps<{ collapse: boolean }>()
    
    const data = [
        {
            icon: 'el-icon-home-filled',
            name: '首页',
            index: '/',
        },
        {
            icon: 'el-icon-check',
            name: '图标选择器',
            index: '/chooseIcon',
        },
        {
            icon: 'el-icon-location',
            name: '省市区选择',
            index: '/chooseArea',
        },
        {
            icon: 'el-icon-sort',
            name: '趋势标记',
            index: '/trend',
        },
        {
            icon: 'el-icon-timer',
            name: '时间选择',
            index: '/chooseTime',
        },
        {
            icon: 'el-icon-bell',
            name: '通知菜单',
            index: '/notification',
        },
        {
            icon: 'el-icon-menu',
            name: '导航菜单',
            index: '/menu',
        },
        {
            icon: 'el-icon-turn-off',
            name: '城市选择',
            index: '/chooseCity',
        },
        {
            icon: 'el-icon-darrow-right',
            name: '进度条',
            index: '/progress',
        },
        {
            icon: 'el-icon-scale-to-original',
            name: '日历',
            index: '/calendar',
        },
        {
            icon: 'el-icon-setting',
            name: '表单',
            index: '/form',
        },
        {
            icon: 'el-icon-setting',
            name: '弹出框表单',
            index: '/modalForm',
        },
        {
            icon: 'el-icon-shopping-bag',
            name: '表格',
            index: '/table',
        },
    ]
    const options = reactive([
        {
            value: '选项1',
            label: '基础组件',
        },
        {
            value: '选项2',
            label: '技术组件',
        },
        {
            value: '选项3',
            label: '业务组件',
        },
    ])
    const value = ref('选项1')
    </script>
    <style lang="scss" scoped>
    
    ::deep .el-radio-button {
        padding: 0.12rem 0.16rem;
    }
    </style>
    
    

    效果如下:

    image.png
    image.png

    兼容后端字段名称

    往往后端的字段名称和前端el-menu默认的name、index,和·我们定义的icon、children不一致。可以优化如下,变成名称自定义:
    修改src\components\baseline\menu\src\index.vue

    <!--
     * @Author: bobokaka
     * @Date: 2021-12-23 00:07:25
     * @LastEditTime: 2021-12-31 17:56:13
     * @LastEditors: Please set LastEditors
     * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
     * @FilePath: \vue3-element-ui-baseline\src\components\baseline\trend\src\itemIndex.vue
    -->
    <template>
        <div>
            <el-menu
                class="el-menu-vertical-demo"
                :default-active="defaultActive"
                :router="router"
                v-bind="$attrs"
            >
                <template v-for="(item, itemIndex) in data" :key="itemIndex">
                    <!-- 一级无二级菜单的菜单栏 -->
                    <el-menu-item
                        v-if="!item[children] || !item[children].length"
                        :index="item[index]"
                    >
                        <component v-if="item[icon]" :is="item[icon]"></component>
                        <span>{{ item[name] }}</span>
                    </el-menu-item>
                    <el-sub-menu
                        v-if="item[children] && item[children].length"
                        :index="item[index]"
                    >
                        <template #title>
                            <component
                                v-if="item[icon]"
                                :is="item[icon]"
                            ></component>
                            <span>{{ item[name] }}</span>
                        </template>
                        <!-- 二级菜单栏 -->
                        <el-menu-item
                            v-for="(item2, index2) in item[children]"
                            :index="item2[index]"
                        >
                            <component
                                v-if="item2[icon]"
                                :is="item2[icon]"
                            ></component>
                            <span>{{ item[name] }}</span>
                        </el-menu-item>
                    </el-sub-menu>
                </template>
            </el-menu>
        </div>
    </template>
    <script lang="ts" setup>
    import { PropType } from 'vue'
    
    const props = defineProps({
        //说明:
        data: {
            required: true,
            type: Array as PropType<any[]>,
        },
        // 默认选中的菜单
        defaultActive: {
            type: String,
            default: '',
        },
        //是否是路由模式 router,
        //是否启用 vue-router 模式
        //启用该模式会在激活导航时以 itemIndex 作为 path 进行路由跳转
        router: {
            type: Boolean,
            default: false,
        },
        //菜单标题的件名
        name: {
            type: String,
            default: 'name',
        },
        //菜单标识的键名
        index: {
            type: String,
            default: 'index',
        },
        // 菜单图标的键名
        icon: {
            type: String,
            default: 'icon',
        },
        // 菜单子菜单的键名
        children: {
            type: String,
            default: 'children',
        },
    })
    // console.log('data:', props.data)
    </script>
    <style lang="scss" scoped>
    .el-menu-vertical-demo:not(.el-menu--collapse) {
        width: 2rem;
        min-height: 4rem;
    }
    svg {
        margin-right: 0.04rem;
    }
    </style>
    
    

    修改src\components\baseline\container\src\navAside\index.vue

    <template>
        <div>
            <bs-menu
                :collapse="collapse"
                :data="data"
                router
                name="text"
                index="code"
                icon="imgSrc"
                children="item"
                :default-active="$route.path"
            ></bs-menu>
        </div>
    </template>
    <script lang="ts" setup>
    import { reactive, ref } from 'vue'
    let props = defineProps<{ collapse: boolean }>()
    
    const data = [
        {
            imgSrc: 'el-icon-home-filled',
            text: '首页',
            code: '/',
        },
        {
            imgSrc: 'el-icon-check',
            text: '图标选择器',
            code: '/chooseIcon',
        },
        {
            imgSrc: 'el-icon-location',
            text: '省市区选择',
            code: '/chooseArea',
        },
        {
            imgSrc: 'el-icon-sort',
            text: '趋势标记',
            code: '/trend',
        },
        {
            imgSrc: 'el-icon-timer',
            text: '时间选择',
            code: '/chooseTime',
        },
        {
            imgSrc: 'el-icon-bell',
            text: '通知菜单',
            code: '/notification',
        },
        {
            imgSrc: 'el-icon-menu',
            text: '导航菜单',
            code: '/menu',
        },
        {
            imgSrc: 'el-icon-turn-off',
            text: '城市选择',
            code: '/chooseCity',
        },
        {
            imgSrc: 'el-icon-darrow-right',
            text: '进度条',
            code: '/progress',
        },
        {
            imgSrc: 'el-icon-scale-to-original',
            text: '日历',
            code: '/calendar',
        },
        {
            imgSrc: 'el-icon-setting',
            text: '表单',
            code: '/form',
        },
        {
            imgSrc: 'el-icon-setting',
            text: '弹出框表单',
            code: '/modalForm',
        },
        {
            imgSrc: 'el-icon-shopping-bag',
            text: '表格',
            code: '/table',
        },
    ]
    const options = reactive([
        {
            value: '选项1',
            label: '基础组件',
        },
        {
            value: '选项2',
            label: '技术组件',
        },
        {
            value: '选项3',
            label: '业务组件',
        },
    ])
    const value = ref('选项1')
    </script>
    <style lang="scss" scoped>
    ::deep .el-radio-button {
        padding: 0.12rem 0.16rem;
    }
    </style>
    
    

    运行后,效果一致。
    将无限层级菜单,也同样修改:
    修改src\components\baseline\menu\src\index.vue

    /*
     * @Author: your name
     * @Date: 2021-12-30 18:07:50
     * @LastEditTime: 2021-12-31 18:09:09
     * @LastEditors: Please set LastEditors
     * @Description: 递归展开层级菜单
     * @FilePath: \vue3-element-ui-baseline\src\components\baseline\menu\src\menu.tsx
     */
    import { defineComponent, PropType, useAttrs, h, resolveComponent } from 'vue'
    import { MenuItem } from './types'
    
    export default defineComponent({
        name: 'infiniteMenu',
        props: {
            //说明:
            data: {
                required: true,
                type: [],
            },
            // 默认选中的菜单
            defaultActive: {
                type: String,
                default: '',
            },
            //是否是路由模式 router,
            //是否启用 vue-router 模式
            //启用该模式会在激活导航时以 index 作为 path 进行路由跳转
            router: {
                type: Boolean,
                default: false,
            },
            //菜单标题的件名
            name: {
                type: String,
                default: 'name',
            },
            //菜单标识的键名
            index: {
                type: String,
                default: 'index',
            },
            // 菜单图标的键名
            icon: {
                type: String,
                default: 'icon',
            },
            // 菜单子菜单的键名
            children: {
                type: String,
                default: 'children',
            },
        },
        setup(props, ctx) {
            //****************** 封装渲染一个无限层菜单的方法 ******************/
            let renderMenu = (data: []) => {
                return data.map((item: any) => {
                    //每个菜单的图标
                    let slots = {
                        title: () => {
                            return (
                                <>
                                    {item[props.icon]
                                        ? h(resolveComponent(item[props.icon]))
                                        : ''}
                                    <span>{item[props.name]}</span>
                                </>
                            )
                        },
                    }
                    //递归渲染children
                    if (item[props.children] && item[props.children].length) {
                        return (
                            <el-sub-menu index={item[props.index]} v-slots={slots}>
                                {/* 递归 */}
                                {renderMenu(item.children)}
                            </el-sub-menu>
                        )
                    }
                    //正常渲染普通的菜单
                    return (
                        <el-menu-item index={item[props.index]}>
                            {/* 这里直接写<item[props.icon]/>无法渲染出来,需要进行如下处理 */}
                            {item[props.icon]
                                ? h(resolveComponent(item[props.icon]))
                                : ''}
                            <span>{item[props.name]}</span>
                        </el-menu-item>
                    )
                })
            }
            let attrs = useAttrs()
            // console.log(attrs)
    
            return () => {
                return (
                    <el-menu
                        default-active={props.defaultActive}
                        router={props.router}
                        {...attrs}
                    >
                        {renderMenu(props.data)}
                    </el-menu>
                )
            }
        },
    })
    

    修改src\components\baseline\container\src\navAside\index.vue

    <!--
     * @Author: bobokaka
     * @Date: 2021-12-20 00:54:44
     * @LastEditTime: 2021-12-31 18:10:22
     * @LastEditors: Please set LastEditors
     * @Description: 左侧菜单栏
     * @FilePath: \vue3-element-ui-baseline\src\components\baseline\container\src\navAside\index.vue
    -->
    <template>
        <div>
            <!-- <bs-menu
                :collapse="collapse"
                :data="data"
                router
                name="text"
                index="code"
                icon="imgSrc"
                children="item"
                :default-active="$route.path"
            ></bs-menu> -->
              <bs-infinite-menu
                :collapse="collapse"
                :data="data"
                router
                name="text"
                index="code"
                icon="imgSrc"
                children="item"
                :default-active="$route.path"
            ></bs-infinite-menu>
            <!-- <el-menu
                default-active="1"
                :collapse="collapse"
                class="el-menu-vertical-demo"
            > -->
            <!-- <el-menu-item index="0">
                    <el-select
                        v-model="value"
                        placeholder="请选择"
                        style="width: 2rem"
                        v-if="!collapse"
                    >
                        <el-option
                            v-for="item in options"
                            :key="item.value"
                            :label="item.label"
                            :value="item.value"
                        ></el-option>
                    </el-select>
                </el-menu-item> -->
            <!-- <el-menu-item index="1">
                    <el-icon><el-icon-menu /></el-icon>
                    <span>首页</span>
                </el-menu-item>
                <el-menu-item index="2">
                    <el-icon><el-icon-menu /></el-icon>
                    <span>图标选择器</span>
                </el-menu-item>
                <el-menu-item index="3">
                    <el-icon><el-icon-menu /></el-icon>
                    <span>省市区选择组件</span>
                </el-menu-item>
                <el-menu-item index="4">
                    <el-icon><el-icon-menu /></el-icon>
                    <span>趋势标记</span>
                </el-menu-item> -->
            <!-- </el-menu> -->
        </div>
    </template>
    <script lang="ts" setup>
    import { reactive, ref } from 'vue'
    let props = defineProps<{ collapse: boolean }>()
    
    const data = [
        {
            imgSrc: 'el-icon-home-filled',
            text: '首页',
            code: '/',
        },
        {
            imgSrc: 'el-icon-check',
            text: '图标选择器',
            code: '/chooseIcon',
        },
        {
            imgSrc: 'el-icon-location',
            text: '省市区选择',
            code: '/chooseArea',
        },
        {
            imgSrc: 'el-icon-sort',
            text: '趋势标记',
            code: '/trend',
        },
        {
            imgSrc: 'el-icon-timer',
            text: '时间选择',
            code: '/chooseTime',
        },
        {
            imgSrc: 'el-icon-bell',
            text: '通知菜单',
            code: '/notification',
        },
        {
            imgSrc: 'el-icon-menu',
            text: '导航菜单',
            code: '/menu',
        },
        {
            imgSrc: 'el-icon-turn-off',
            text: '城市选择',
            code: '/chooseCity',
        },
        {
            imgSrc: 'el-icon-darrow-right',
            text: '进度条',
            code: '/progress',
        },
        {
            imgSrc: 'el-icon-scale-to-original',
            text: '日历',
            code: '/calendar',
        },
        {
            imgSrc: 'el-icon-setting',
            text: '表单',
            code: '/form',
        },
        {
            imgSrc: 'el-icon-setting',
            text: '弹出框表单',
            code: '/modalForm',
        },
        {
            imgSrc: 'el-icon-shopping-bag',
            text: '表格',
            code: '/table',
        },
    ]
    const options = reactive([
        {
            value: '选项1',
            label: '基础组件',
        },
        {
            value: '选项2',
            label: '技术组件',
        },
        {
            value: '选项3',
            label: '业务组件',
        },
    ])
    const value = ref('选项1')
    </script>
    <style lang="scss" scoped>
    ::deep .el-radio-button {
        padding: 0.12rem 0.16rem;
    }
    </style>
    
    

    运行效果一致:

    image.png

    相关文章

      网友评论

        本文标题:【Vue3+Vite+TS】9.0 改造项目整体结构

        本文链接:https://www.haomeiwen.com/subject/enncqrtx.html