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>
相关推荐
NCDS程序员5 小时前
v-model: /v-model/ :(v-bind)三者核心区别
前端·javascript·vue.js
夏幻灵6 小时前
CSS三大特性:层叠、继承与优先级解析
前端·css
小杨同学呀呀呀呀6 小时前
Ant Design Vue <a-timeline>时间轴组件失效解决方案
前端·javascript·vue.js·typescript·anti-design-vue
华玥作者14 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_14 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠14 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang2015092815 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC16 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务16 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整16 小时前
面试点(网络层面)
前端·网络