Skip to content
鼓励作者:欢迎打赏犒劳

03-elementPlus

主要记录一下elementPlus相关的问题

修改css样式

https://blog.csdn.net/wangyile4399/article/details/115402411

直接加::v-deep

text
<style scoped>
    ::v-deep(.el-input__inner){
        background: aqua ;
        font-size: 30px ;
    }
</style>

表格合并

表格合并+自定义表头

vue
<template>
    <div class="table-header-tool">
        <el-select
                v-model="chooseFiledList"
                multiple
                clearable
                collapse-tags
                placeholder="Select"
                popper-class="custom-header"
                :max-collapse-tags="1"
                style="width: 200px"
        >
            <div style="margin: 10px">
                <el-checkbox
                        v-model="checkAll"
                        :indeterminate="indeterminate"
                        @change="handleCheckAll"
                >
                    全选
                </el-checkbox>
            </div>
            <el-option
                    v-for="item in filedTitle"
                    :key="item"
                    :label="item"
                    :value="item"
            />
        </el-select>
    </div>
    <el-table :data="tableData" border :span-method="objectSpanMethod">
        <el-table-column v-if="chooseFiledList.indexOf('date')!=-1" prop="date" label="Date" />
        <el-table-column v-if="chooseFiledList.indexOf('name')!=-1" prop="name" label="Name" />
        <el-table-column v-if="chooseFiledList.indexOf('status')!=-1" prop="status" label="Status" />
    </el-table>
</template>

<script setup>
    import {ref, onMounted, nextTick, watch} from 'vue';
    import axios from 'axios';

    //是否全选
    const checkAll = ref(true)
    //是否半选
    const indeterminate = ref(false)
    //选中展示的字段
    const chooseFiledList = ref(['date','name','status'])
    //字段下拉列表
    const filedTitle = ref(['date','name','status'])

    //全选选中事件
    const handleCheckAll = (val) => {
        indeterminate.value = false
        if (val) {
            chooseFiledList.value = filedTitle.value.map(item => item)
        } else {
            chooseFiledList.value =[]
        }
    }
    //监控字段
    watch(chooseFiledList, (val) => {
        if (val.length === 0) {
            checkAll.value = false
            indeterminate.value = false
        } else if (val.length === filedTitle.value.length) {
            checkAll.value = true
            indeterminate.value = false
        } else {
            indeterminate.value = true
        }

        nextTick(()=>{
            //这边使用这个是为了 el-table-column中使用了v-if来判断和显示
            //如果不调用此方法的话,会出现样式错乱和滚动条无缘无故的出现等问题
            app.proxy.$refs.tableRef.doLayout()
        })
    })



    const tableData = ref([]);
    let hbObj = ref({})
    let propertyList = [
        'date'
    ]
    // 从后端获取数据
    const fetchData = async () => {
        // 示例:使用 axios 从后端获取数据
        const response = await axios.get('/2.json');
        tableData.value = response.data;
        hbObj.value = computeCell(response.data,propertyList)
    };

    // 合并单元格的逻辑
    const objectSpanMethod = ({
                                  row,
                                  column,
                                  rowIndex,
                                  columnIndex,
                              }) => {
        // console.log(row,column,rowIndex,columnIndex)
        let property = column.property

        if (propertyList.indexOf(property) != -1){
            let aList = hbObj.value[property]
            const fRow = aList[rowIndex]
            const fCol = fRow > 0 ? 1 : 0
            return {
                rowspan: fRow, // 合并的行数
                colspan: fCol // 合并的列数,为0表示不显示
            }
        }else{
            return [1,1]
        }
    }
    const computeCell = (data,propertyList) => {

        let result = {}
        for (let j = 0; j < propertyList.length; j++) {
            let property = propertyList[j]
            let list = []
            let curIndex = 0
            for (let i = 0; i < data.length; i++) {
                if (i == 0){
                    list.push(1)
                    curIndex = 0
                }else{
                    if (data[i][property] == data[i - 1][property]){
                        list[curIndex] += 1;
                        list.push(0);
                    }else{
                        list.push(1);
                        curIndex = i;
                    }
                }
            }
            result[property] = list
        }
        return result;
    }

    onMounted(() => {
        fetchData();
    });

</script>

<style scoped>
    .table-header-tool{
        display: flex;
        justify-content: end;
    }
</style>

表单校验

注意

  1. 需要 :rules="rules"

  2. 需要加上prop="account"

  3. 需要ref="registerFormRef"

vue
<template>
    <el-button type="primary" @click="dialogRegisterVisible = true">注册</el-button>

    <el-dialog v-model="dialogRegisterVisible"  title="用户注册" width="500">
        <el-form :model="registerForm" :rules="rules" ref="registerFormRef">
            <el-form-item label="账号" label-width="60px" prop="account">
                <el-input v-model="registerForm.account" autocomplete="off" clearable/>
            </el-form-item>
            <el-form-item label="密码" label-width="60px">
                <el-input v-model="registerForm.password" type="password" clearable autocomplete="off"/>
            </el-form-item>
            <el-form-item label="邮箱" label-width="60px">
                <el-input v-model="registerForm.email" clearable autocomplete="off"/>
            </el-form-item>

        </el-form>
        <template #footer>
            <div class="dialog-footer">
                <el-button @click="dialogRegisterVisible = false">取消</el-button>
                <el-button type="primary" @click="registerUser()">
                    注册
                </el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup>
    import {reactive, ref} from 'vue'

    let dialogRegisterVisible = ref(false)
    const registerFormRef= ref(null)
    const registerForm = reactive({
        account: '',
        password: '',
        email: '',
    })
    const rules = {
        account: [
            {required: true, message: '账号必填', trigger: 'blur'},
            { min: 5, max: 10, message: '账号必须是5-10位字符', trigger: 'blur' }
        ],
        password: [
            {
              pattern: /^\S{6,15}$/,
              message: '密码必须是6-15位非空字符',
              trigger: 'blur'
            }
          ]
    }

    function registerUser() {
      registerFormRef.value.validate((valid) => {
        if (valid) {
          // 业务逻辑
        }
      });
    }

</script>

上传图片

上传单个图片

在使用 Element Plus 的 <el-upload> 组件时,如果你设置了 :show-file-list="false", 默认情况下不会显示文件列表以及移除按钮。但是,你仍然可以通过自定义上传区域来实现移除图标的显示。

html
<template>
    <el-upload
            class="avatar-uploader"
            list-type="picture-card"
            :show-file-list="false"
            :http-request="uploadFile"
    >
        <div v-if="imageUrl" class="preview-container">
            <img :src="imageUrl" class="avatar" />
            <el-icon @click.stop="handleRemove" class="remove-icon"><Close /></el-icon>
        </div>
        <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
    </el-upload>
</template>

<script  setup>
    import { ref } from 'vue'
    import { Plus,Close } from '@element-plus/icons-vue'


    const imageUrl = ref('')

    //图片上传
    let uploadFile = (params) => {
        console.log(params)
        console.log(URL.createObjectURL(params.file))
        imageUrl.value = URL.createObjectURL(params.file)
    }
    //移除图片
    const handleRemove = (uploadFile) => {
        console.log(uploadFile)
        imageUrl.value = '';
    }
</script>

<style scoped>
    .avatar-uploader .avatar {
        width: 100%;
        height: 100%;
        display: block;
    }
    .preview-container {
        position: relative;
        width: 148px;
        height: 148px;
    }

    .remove-icon {
        position: absolute;
        top: 0px;
        right: 0px;
        background-color: #fff;
        border-radius: 50%;
        padding: 4px;
        cursor: pointer;
    }
</style>

上传多个图片

vue
<template>
  <el-upload
      v-model:file-list="fileList"
      list-type="picture-card"
      :limit="5"
      :on-preview="handlePictureCardPreview"
      :http-request="uploadFile"
      :on-remove="handleRemove"
  >
    <el-icon><Plus /></el-icon>
  </el-upload>

  <el-dialog v-model="dialogVisible">
    <img w-full :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>

<script  setup>
import { ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'


const fileList = ref([
  {
    url: 'https://dummyimage.com/200x100&text=PIC1',
  },
  {
    url: 'https://dummyimage.com/200x100&text=PIC2',
  },
  {
    url: 'https://dummyimage.com/200x100&text=PIC3',
  },
])

const dialogImageUrl = ref('')
const dialogVisible = ref(false)

const handleRemove = (uploadFile, uploadFiles) => {
  console.log(uploadFile, uploadFiles,fileList)
}
//图片上传 ,因为组件默认会增加本地图片,所以,需要先删除掉默认的图片,加入成功上传到服务器的图片
let uploadFile = (params) => {
  fileList.value = fileList.value.filter(m => m.uid !== params.file.uid)
  // 需要换成真实的上传接口,接口上传成功获取url
  // uploadFileApi(params.file).then(res => {
  //    if (res.code === 200) {
  //      fileList.value.push({
  //        url: res.data
  //      })
  //    }
  // })
  console.log(params,fileList)
}
//预览图片
const handlePictureCardPreview = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url
  dialogVisible.value = true
}
</script>

封装的上传组件

父组件

vue
<script>
import UploadImages from "@/components/UploadImages/index.vue";

//表单属性
let form = ref({
  id: null,
  name: '',
  url: '',
  img:'',
})
//编辑回显用的
const imgList = ref([])
//获取组件图片的url
const getImageList = (imgList) => {
  form.value.img = imgList?.[0]?.url ?? ''
}
</script>
<template>
    <UploadImages :imgList="imgList"  :limit="5"   @getImageList="getImageList"/>
</template>

UploadImages.vue

vue
<script setup>
  import {defineProps, ref,defineEmits} from 'vue'
  import { imageUpload } from '@/api/upload'

  // 使用defineEmits来接收来自父组件的方法
  const emit = defineEmits(['getImageList'])

  // 声明props
  const props = defineProps({
    imgList: {
      type: Array,
      default: () => {
        return []
      }
    },
    limit:{
      type: Number,
      default: () => {
        return 1
      }
    }
  });
  //图片列表
  const fileList = ref(props.imgList ?? [])
  const dialogImageUrl = ref('')
  const dialogVisible = ref(false)
  //图片上传
  let uploadFile = (params) => {
    fileList.value = fileList.value.filter(m => m.uid !== params.file.uid)
    // 根据后台需求数据格式
    const formImg = new FormData()
    // 文件对象
    formImg.append('file', params.file)

    imageUpload(formImg).then(res => {
      if (res.code === 200) {
        fileList.value.push({
          url: res.data.url,
          name: res.data.filename
        })
        //调用父级的方法
        emit('getImageList', fileList.value)
      }
    })
  }
  //预览图片
  const handlePictureCardPreview = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url
    dialogVisible.value = true
  }
  //移除图片
  const handleRemove = (uploadFile, uploadFiles) => {
    console.log(uploadFile, uploadFiles)
    //调用父级的方法
    emit('getImageList', fileList.value)
  }
</script>

<template>
  <el-upload
      v-model:file-list="fileList"
      list-type="picture-card"
      :limit="limit"
      :on-preview="handlePictureCardPreview"
      :http-request="uploadFile"
      :on-remove="handleRemove"
  >
    <el-icon><Plus /></el-icon>
  </el-upload>

  <el-dialog v-model="dialogVisible">
    <img w-full :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>

<style scoped lang="scss">

</style>

upload.js 上传接口

js
import request from '@/utils/system/request'

// 上传文件接口
export function imageUpload(data) {
    return request({
        url: '/upload/file',
        method: 'post',
        // baseURL: '/mock',
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        data
    })
}

自定义Icon图标

新建组件 CustomIcon.vue

vue
<template>
    <div :style="iconStyle">
        <img :src="iconSrc" alt="icon" class="custom-icon" />
    </div>
</template>

<script>
    export default {
        name: 'CustomIcon',
        props: {
            iconSrc: {
                type: String,
                required: true,
            },
            size: {
                type: Number,
                default: 24,
            },
        },
        computed: {
            iconStyle() {
                return {
                    width: `${this.size}px`,
                    height: `${this.size}px`,
                    display: 'inline-block',
                };
            },
        },
    };
</script>

<style scoped>
    .custom-icon {
        width: 100%;
        height: 100%;
        object-fit: contain;
    }
</style>

使用

html
 <CustomIcon iconSrc="/favicon.ico" :size="32" />

element-plus分页组件改中文

1、引入官方的语言包

2、在App.vue中进行设置

vue3
<el-config-provider  :locale="zhCn">
    <router-view></router-view>
</el-config-provider>
<script setup lang="ts">
    import zhCn from "element-plus/lib/locale/lang/zh-cn";
    //如果报错,可以试下下面的
    //import zhCn from 'element-plus/es/locale/lang/zh-cn'
</script>

自定义语言包

cn.js

js
// src/locales/zh-cn.js
export default {
  el: {
    pagination: {
      goto: '跳转到',
      pageClassifier: '页',
	  total:'共 {total} 条记录'
    },
  },
};

在main.js中进行引入

js
import locale from "path/cn";

配置语言

js
app.use(ElementPlus, {
    locale: locale  // 一定要加上,不然无效
})

完整代码

js
import locale from "path/cn";
const app = createApp(App)
app.use(ElementPlus, {
    locale: locale  // 一定要加上,不然无效
})
app.mount('#app')

如有转载或 CV 的请标注本站原文地址