12.15 element-plus的一些组件(上)

El-Plus的面包屑导航组件

HTML 复制代码
<template>
  <el-breadcrumb separator="/">
    <el-breadcrumb-item :to="{ path: '/' }">homepage</el-breadcrumb-item>
    <el-breadcrumb-item>
        <a href="/">promotion management</a>
    </el-breadcrumb-item>
    <el-breadcrumb-item>promotion list</el-breadcrumb-item>
    <el-breadcrumb-item>promotion detail</el-breadcrumb-item>
  </el-breadcrumb>
</template>

面包屑动态渲染

数据结构

JavaScript 复制代码
// 面包屑列表
//  首页 / 学生管理 / 学员管理
const list = ref([
    {
        title: '首页',
        path: '/dashboard/console'
    },
    {
        title: '学生管理',
        path: '/student/classAdmin'
    },
    {
        title: '学员管理',
        path: '/student/studentAdmin'
    }
])

动态渲染

HTML 复制代码
<template>
    <el-breadcrumb separator="/">
        <el-breadcrumb-item
            v-for="item in list"
            :to="{ path: item.path }"
        >
            {{item.title}}
        </el-breadcrumb-item>
    </el-breadcrumb>
</template>

监听路由变化

JavaScript 复制代码
import { watch,ref } from 'vue';
import { useRoute } from 'vue-router'
const route = useRoute()
//监听路由变化
watch(route, (to) => {
    console.log(to)  //路由记录
}, {
    immediate: true
})  

需求分析

/** 分类讨论: 进入首页 /dashboard/console to.matched[0].path = '/dashboard/console' 进入只有一级菜单的路由 /notice/index breadcrumbList:['公告管理'] 进入有二级菜单的路由 /echarts/bar breadcrumbList: ['图表管理','柱状图] */

代码实现

JavaScript 复制代码
//监听路由变化
watch(route, (to) => {
    //每次切换路由时,清空以前的列表,只保留首页
    list.value = [{
        title: '首页',
        path: '/dashboard/console'
    }]
    // 如果path= '/dashboard/console',则说明当前是首页,不需要处理
    if (to.fullPath === '/dashboard/console') return;
    //只有一级菜单,则只添加一次
    if (to.matched[0].children.length === 1) {
        list.value.push({
            title: to.meta.title,
            path: to.fullPath
        })
        return;
    } else {
        //有二级菜单
        to.matched.forEach(item => {
            let path;
            // /首页/学生管理/班级管理 (学生管理下的第一个菜单 )
            // /首页/学生管理/学员管理
            // 如上,单击学生管理,应该跳转至班级管理,所以在学生管理的路由配置中添加
            // meta {
            //     home: '/student/studentAdmin'
            // }
            if (item.meta.home){
                path = item.meta.home
            }else{
                path = item.fullPath
            }
            list.value.push({
                title: item.meta.title,
                path
            })
        })
    }
}, {
    immediate: true
}) 

实现国际化代码

HTML 复制代码
<script lang="ts" setup>
    import { computed, ref } from 'vue'
    import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
    import en from 'element-plus/dist/locale/en.mjs'
    const language = ref('zh-cn')
    const locale = computed(() => (language.value === 'zh-cn' ? zhCn : en))
    const toggle = () => {
      language.value = language.value === 'zh-cn' ? 'en' : 'zh-cn'
    }
</script>
<template>
   <el-config-provider :locale="locale">
      <el-date-picker type="date" placeholder="Pick a date" :default-value="new Date(2010, 9, 1)" />
   </el-config-provider>
</template>

日期组件国际化【添加中英文切换功能】

**国际化之前

![[360X360.PNG]]

**国际化之后

![[360X360 (1).PNG]]

添加中英文切换功能

图片上传

创建上传图片的组件

在upload/index.vue

HTML 复制代码
<script setup>

</script>

<template>
   <div class="upload">
    图片上传
   </div>
</template>
<style lang="scss" scoped>

</style>

添加路由

JavaScript 复制代码
// 文件上传-一级路由
{
    path: '/upload',
    name: 'upload',
    component: () => import('@/pages/layout/index.vue'),
    children:[{
        // /moreLang/index
        path: 'index',
        name: 'uploadimg',
        component: () => import('@/pages/upload/index.vue'),
    }]
},

配置图片上传模板

HTML 复制代码
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'

const imageUrl = ref('')

// 通过header头传递token
const headers = ref({
    "Authorization": "Bearer " + sessionStorage.getItem('token')
});

// 上传成功之后的处理方法
const handleAvatarSuccess = (response, uploadFile) => {
    imageUrl.value = URL.createObjectURL(uploadFile.raw)
}

// 上传之前的格式验证:是否为图片,大小是否在2MB
const beforeAvatarUpload = (rawFile) => {
    if (rawFile.type !== 'image/jpeg') {
        ElMessage.error('Avatar picture must be JPG format!')
        return false
    } else if (rawFile.size / 1024 / 1024 > 2) {
        ElMessage.error('Avatar picture size can not exceed 2MB!')
        return false
    }
    return true
}
</script>

<template>
    <!--
    action:后端的路径地址
    show-file-list:是否显示上传成功的文件列表
    on-success:当文件上传成功之后
    before-upload:文件上传之前
    headers:添加headers值,里面主要用来添加token
    -->
    <el-upload class="avatar-uploader" 
    action="/api/upload" 
    :show-file-list="false" 
    :on-success="handleAvatarSuccess"
    :before-upload="beforeAvatarUpload" 
    :headers="headers">
        <img v-if="imageUrl" :src="imageUrl" class="avatar" />
        <el-icon v-else class="avatar-uploader-icon">
            <Plus />
        </el-icon>
    </el-upload>
</template>
  
<style scoped>
.avatar-uploader .avatar {
    width: 178px;
    height: 178px;
    display: block;
}
</style>
  
<style>
.avatar-uploader .el-upload {
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
    border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    text-align: center;
}
</style>
  

注意:如果想要自定义上传方式,可以使用下面方式

HTML 复制代码
<el-upload class="avatar-uploader" action="#" :show-file-list="true" :http-request="changeHeader"
            :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :headers="headers">
    <img v-if="imageUrl" :src="imageUrl" class="avatar" />
    <el-icon v-else class="avatar-uploader-icon">
        <Plus />
    </el-icon>
</el-upload>
<script>
    let changeHeader = async (params) => {
    let fileObject = params.file
    let pic = new FormData()
    pic.append('files', fileObject);
    let url = '/api/uploadImg'
    let config = {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    }
    
    axios({
        method: 'post',
        url: url,
        data: pic,
        config: config
    }).then(response => {
        console.log(response)
    }).catch(error => {
        console.log(error)
    })
}
</script>


# Tab标签页

```HTML
<script setup>
/**
 * 分类讨论:
 * 1. 首次进入后台管理主页   ['首页']
 * 2. 切换路由,先判断是否已存在,
 * 如果不存在则在tab标签上添加当前路由的标题  ['首页','公告管理','图片上传'] , 在标题上还要绑定路由,
 * 如果已经存在,则只需要获取路由对应的索引,处理高亮
 * 3. 控制高亮
 * 4. 删除: 当前标签从tabList中删除掉,
 */
import { watch, ref,Ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute()
const router = useRouter()

interface IRoute{
    fullPath:String,
    name?:String | any,
    path:String | any,
    title?:String
}

// tabList = [{},{},{}]
const tabList:Ref = ref([])
const activeIndex = ref(0)
//判断是否重复
const isRepeat = (to:IRoute) => {
    return tabList.value.some((item:IRoute) => item.path === to.fullPath)
}

watch(route, (to) => {
    console.log(to)
    //先判断是否重复
    if (!isRepeat(to)) {
        //不重复
        tabList.value.push({
            title: to.meta.title,
            path: to.fullPath
        })
        activeIndex.value = tabList.value.length - 1
    } else {
        // 重复
        activeIndex.value = tabList.value.findIndex((item:IRoute)=> item.path === to.fullPath)
    }
}, {
    immediate: true
})

//跳转
const jump = (item:IRoute) => {
    router.push(item.path)
}
//关闭
const handleClose = (index) => {
    //删除前面的
    if (index < activeIndex.value) {
        tabList.value.splice(index, 1)
        activeIndex.value = activeIndex.value - 1
        return;
    }
    if (index === activeIndex.value && index !== tabList.value.length - 1) {
        tabList.value.splice(index, 1)
        router.push(tabList.value[activeIndex.value].path)
        return;
    }
    //判断当前删除的是最后一个,而且是高亮的
    if (index === tabList.value.length - 1 && index === activeIndex.value) {
        //是最后一个
        tabList.value.splice(index, 1)
        activeIndex.value = tabList.value.length - 1
        router.push(tabList.value[activeIndex.value].path)
        return;
    }
    //删后面的
    if (index > activeIndex.value) {
        tabList.value.splice(index, 1)
    }

}
</script>

<template>
    <div class="tabs">
        <!-- <el-tag type="danger" closable>Tag 3</el-tag>
        <el-tag type="info" closable>Tag 3</el-tag> -->
        <el-tag v-for="(item, index) in tabList" :type="activeIndex === index ? 'danger' : 'info'" closable
            @click="jump(item)" @close="handleClose(index)">{{ item.title }}</el-tag>
    </div>
</template>

<style lang="scss" scoped></style>
相关推荐
JS_GGbond4 小时前
JavaScript原型链:一份会“遗传”的家族传家宝
前端·javascript
前端达人4 小时前
CSS终于不再是痛点:2026年这7个特性让你删掉一半JavaScript
开发语言·前端·javascript·css·ecmascript
JS_GGbond4 小时前
当JS拷贝玩起了“俄罗斯套娃”:深拷贝与浅拷贝的趣味对决
前端·javascript
code_YuJun4 小时前
脚手架开发工具——npmlog
前端
donecoding4 小时前
掌握 :focus-within,让你的AI对话输入体验更上一层楼!
前端·人工智能
快乐星球喂4 小时前
使用nrm管理镜像
前端
用户4099322502124 小时前
Vue3动态样式管理:如何混合class/style绑定、穿透scoped并优化性能?
前端·ai编程·trae
小徐不会敲代码~4 小时前
Vue3 学习2
前端·javascript·学习
m0_740043734 小时前
Vue2 语法糖简洁指南
前端·javascript·vue.js