【Element UI】使用问题记录

【Element UI】使用问题记录

转载:https://www.cnblogs.com/yangchongxing/p/10750994.html

下载地址:

https://unpkg.com/browse/element-ui@2.11.1/

https://unpkg.com/element-ui@2.11.1/lib/index.js

https://unpkg.com/element-ui@2.11.1/lib/theme-chalk/index.css

=============================================================

1、el-cascader 级联选择器

2、重置 form 表单字段的值 或 清除验证结果

3、form 表单的校验

4、强制组件渲染

5、设置光标 focus

6、校验及规则

7、元素默认border-color

8、自定义input样式

9、from表单数组对象元素的校验

10、视频 video 自动适应 el-col 宽度

11、el-table 操作

12、el-tree 操作

13、谷歌浏览器 input 自动填充颜色改变或透明

14、可输入可选择级联器组件

15、展开el-tree指定的结点

16、日期、时间、日期时间控件

17、表格树 el-table-tree-column 问题

18、el-dialog弹出框的body设置高度

=============================================================

1、el-cascader 级联选择器

a. 显示无法清空

<el-cascader 
    ref="mycascader" 
    :options="dataArray" 
    v-model="selectData"
    :show-all-levels="false" expand-trigger="click"
    clearable
    change-on-select>
</el-cascader>

定义一个 ref ,使用 clearValue 方法清空

let obj = {};
obj.stopPropagation = () =>{};
this.$refs.mycascader.clearValue(obj);

clearValue 源码如下,此处clearValue需要传入一个事件对象 这里是自己模拟一个事件对象来避免报错

clearValue: function clearValue(ev) {
    ev.stopPropagation();
    this.handlePick([], true);
}

b. 每一层都选择

追加 change-on-select 属性,去掉则只能选择叶子结点

c. 选中指定的值

let position = [];
position.push(value);
this.$refs.mycascader.handlePick(position);

d. 显示和隐藏菜单

this.$refs.mycascader.showMenu();
this.$refs.mycascader.hideMenu();

e. 实现可输入可选择

<template>
    <el-cascader filterable ref="cstmInputDepartmentDascader" :options="departmentCascader" v-model="departmentValue"
                 :props="{ checkStrictly: true }"
                 :show-all-levels="showAllLevels"
                 :size="showSize"
                 :debounce="500" style=" 100%"
                 :before-filter="beforeFilterDepartment"
                 @blur="blurDepartment"
                 @focus="focusDepartment"
                 @change="changeDepartment"
                 @visible-change="visibleChange"
                 :placeholder="showPlaceholder" clearable
    ></el-cascader>
</template>

<script>
    import {deepClone} from '@/util/util';
    import {getCascaderAttach} from '@/api/admin/department';

    export default {
        name: "input-department-cascader",
        props: {
            value: {},
            showAllLevels: {
                type: Boolean,
                default: false
            },
            showSize: {
                type: String,
                default: 'medium'
            },
            showPlaceholder: {
                type: String,
                default: ''
            }
        },
        data() {
            return {
                departmentList: [],
                departmentCascader: [],
                departmentCascaderBack: [],
                departmentCascaderLength: undefined,
                departmentValue:[],
                inputDepartmentName: undefined,
                increment: 1
            }
        },
        created() {
            this.getDepartmentCascader();
        },
        mounted() {
            this.init();
        },
        methods: {
            getDepartmentCascader() {
                getCascaderAttach().then(response => {
                    // 部门列表数据 id,parentId,treePosition, 根节点parentId是0,treePosition没有
                    this.departmentList = response.data.attachData;
                    // 部门级联数据 label,value,children,disabled
                    this.departmentCascader = response.data.cascaderData;
                    this.departmentCascaderLength = this.departmentCascader.length;
                    // 部门级联数据备份
                    this.departmentCascaderBack = deepClone(this.departmentCascader);
                    this.init();
                })
            },
            init() {
                if (!this.value) return;
                let value = [];
                let list = deepClone(this.departmentCascaderBack);
                let department = this.getDepartmentById(this.value);
                // 没有找到就认为是输入的数据
                if (!department) {
                    list.push(this.getItem(this.value));
                    value.push(this.value);
                } else {
                    if (department.treePosition) {
                        value = department.treePosition.substr(1).split('&');
                    }
                    value.push(this.value);
                }
                this.departmentCascader = list;
                this.departmentValue = value;
            },
            getDepartmentById(id) {
                let department = undefined;
                if (this.departmentList && id) {
                    for (let item of this.departmentList) {
                        if (id === item.id) {
                            department = deepClone(item);
                            break;
                        }
                    }
                }
                return department;
            },
            getItem(name) {
                return {
                    value: name,
                    label: name,
                    children: undefined,
                    disabled: false
                }
            },
            beforeFilterDepartment: function(value) {
                this.inputDepartmentName = value;
                return false;
            },
            blurDepartment() {
                if (!this.inputDepartmentName) return;
                this.inputDepartmentName = this.inputDepartmentName.trim();
                if (this.inputDepartmentName === "") return;
                this.$set(this.departmentCascader, this.departmentCascaderLength, this.getItem(this.inputDepartmentName));
                this.departmentValue = [this.inputDepartmentName];
                this.inputDepartmentName = undefined;
                this.changeDepartment(this.departmentValue);
            },
            focusDepartment() {
                this.$refs.cstmInputDepartmentDascader.$refs.input.$refs.input.select();
            },
            changeDepartment(v) {
                if (v && v.length > 0) {
                    this.$emit('input', v[v.length - 1]);
                } else {
                    this.$emit('input', '');
                }
            },
            visibleChange(flag) {
                if (flag) return;
                if (this.departmentValue && this.departmentValue.length > 0) {
                    let departmentId = this.departmentValue[this.departmentValue.length - 1];
                    let departmentName = '';
                    let department = this.getDepartmentById(departmentId);
                    if (department) {
                        departmentName = department.name;
                    } else {
                        departmentName = departmentId;
                    }
                    this.$emit('departmentChange', departmentId, departmentName);
                } else {
                    this.$emit('departmentChange', '', '');
                }

            },
            setDepartmentValue(v) {
                this.departmentValue = v;
            }
        }
    }
</script>

<style scoped>

</style>

filterable 开启过滤,也就是变成可输入

before-filter 筛选之前的钩子,参数为输入的值,若返回 false 或者返回 Promise 且被 reject,则停止筛选

blur 失去焦点

f、获取当前的 label

<el-cascader ref="myCascader" :options="myList" v-model="myPosition" @change="myChange" size="small"></el-cascader>

getMyList(){
    this.myList = [];
    // 查询结果
    getMyListFromDB().then(response => {
        this.myList = response.data;
        if(this.myList.length > 0){
            let v = [];
            this.getDefault(v, this.myList);//取出默认第一个的数组
            this.myPosition = v;//选中第一个
            if (v.length > 0) {
                let selectValue = v[v.length - 1];
                let selectLabel = this.currentLabels(v);
            }
        }
    })
},
getDefault(result, list) {
    if (list) {
        result.push(list[0].value);
        this.getDefault(result, list[0].children);
    }
},
currentLabels(v) {
    let options = this.myList;
    let labels = [];
    v.forEach(value => {
        const targetOption = options && options.filter(option => option['value'] === value)[0];
        if (targetOption) {
            labels.push(targetOption['label']);
            options = targetOption['children'];
        }
    });
    // 拼接标签数组
    let label = this.$refs.myCascader.showAllLevels ? labels.join('/') : labels[labels.length - 1];
    return label;
},
myChange(v){
    if (v.length > 0) {
        let selectValue = v[v.length - 1];
        let selectLabel = this.currentLabels(v);
    }
}

g、选中可输入级联中的所有值

this.$refs.mycascader.$refs.input.$refs.input.select();

2、重置 form 表单字段的值 或 清除验证结果

validate

对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise

Function(callback: Function(boolean, object))

例:this.$refs['myForm'].validate((valid, obj) => {});

validateField

对部分表单字段进行校验的方法

Function(props: array | string, callback: Function(errorMessage: string))

例:this.$refs['myForm'].validateField('myField', errorMsg => {});

resetFields

对整个表单进行重置,将所有字段值重置为初始值并移除校验结果

例:this.$refs['myForm'].resetFields();

clearValidate

移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果

Function(props: array | string)

例:

this.$refs['myForm'].clearValidate();
this.$refs['myForm'].clearValidate(["myField1","myField2"]);

3、form 表单的校验

表单定义 ref="myForm"

Form Methods 表单方法

validate  对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise Function(callback: Function(boolean, object))

validateField  对部分表单字段进行校验的方法 Function(props: array)

清除表单值和校验信息
this.$refs['myForm'].resetFields();


清除表单校验信息
this.$refs['myForm'].clearValidate();


校验单校
this.$refs['myForm'].validate(valid => {
  if(valid) {
    // 检验成功,没有问题
  } else {
    // 校验失败,有错误
  }
});


校验字段
this.$refs['myForm'].validateField('name', errorMsg => {
  if (!errorMsg) {
  } else {
    callback(new Error("请输入姓名"));
  }
});

跟规则校验,nameEnable == 0时不校验,其他时候校验

const checkName = (rule, value, callback) => {
    if (/^[u4e00-u9fa5]{2,4}$/.test(value)) {
        callback();
    } else {
        callback(new Error('请输入汉字'));
    }
};        
settingRules: {
    name: [
        {required: true, message: '请输入姓名'},
        {validator: checkName, trigger: ['blur','change']}
    ],
}
<el-form-item label="姓名" prop="name" ref="nameField" :rules="nameEnable == 0 ? [] : userRules.name">
    <el-input v-model="user.name" maxlength="4"></el-input>
</el-form-item>

4、强制组件渲染

this.$forceUpdate();

5、设置光标 focus

在vue中并不是每次数据改变都会触发更新dom,而是将这些操作都缓存在一个队列,在一个事件循环结束之后,刷新队列,统一执行dom更新操作。 而如果想在DOM状态更新后做点什么,则需要用到nextTick。在vue生命周期的created()钩子函数进行的DOM操作要放在Vue.nextTick()的回调函数中,因为created()钩子函数执行的时候DOM并未进行任何渲染,而此时进行DOM操作是徒劳的,所以此处一定要将DOM操作的JS代码放进Vue.nextTick()的回调函数中。

通过下面的方式设置光标

this.$nextTick(() => {
    this.$refs['viewFocus'].focus();
});

6、校验

userRules: {
    name: [
        {required: true, message: '请输入名称'}
        {validator: checkName, trigger: ['blur','change']}
    ]
}
const checkName = (rule, value, callback) => {
    isNameExist(name: name}).then(response => {
        if (response.status == 200 && response.data) {
            callback(new Error(response.message));
            return;
        }
    });
    callback();
};

 全局匹配非数字,/[^d]/g.test(value) true说明有非数字需要提示错误,false说明都是数字验证通过

7、元素默认border-color

正常:border-color: #dcdfe6;

焦点:border-color: #409EFF;

出错:border-color: #f56c6c;

8、自定义input样式

input::-webkit-input-placeholder {
    color: #C0C4CC;
    font-size: 14px;
}
input:-moz-placeholder {
    color: #C0C4CC;
    font-size: 14px;
}
input:-ms-input-placeholder {
    color: #C0C4CC;
    font-size: 14px;
}

.imageNameInput {
    margin-top: 2px;
    -webkit-appearance: none;
    background-color: #fff;
    background-image: none;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    color: #606266;
    display: inline-block;
    color: #303133;
    font-size: 14px;
    height: 40px;
    line-height: 40px;
    outline: 0;
    padding: 0 15px;
    -webkit-transition: border-color .2s cubic-bezier(.645,.045,.355,1);
    transition: border-color .2s cubic-bezier(.645,.045,.355,1);
    width: 160px;
}
.imageNameInput input[type=text]:focus{
    outline: 1px solid #409EFF;
}

9、from表单数组对象元素的校验

直接给prop绑定为数组下的名称

参考文章:https://www.cnblogs.com/beileixinqing/p/10969828.html

model: {
    images: undefined,
    imageArray: []
}

imageArray的属性{name: undefined, url: undefined, del: false}

<el-form-item label="图片" prop="images">
    <el-input v-model="model.images"></el-input>
    
    <div v-for="(o,i) in model.imageArray" class="image-uploader">
        <el-form-item :prop="`imageArray[${i}].name`" :rules="{ required: true, message: '图片名称', trigger: 'blur' }">
            <img :src="o.url" class="image-add">
            <el-input v-model="o.name" maxlength="20"></el-input>
        </el-form-item>
    </div>
</el-form-item>

10、视频 video 自动适应 el-col 宽度

给视频指定样式即可

参考文档:https://blog.csdn.net/wuqingyou_w/article/details/51671356

video {
        width: 100%;
        height: 100%;
        object-fit:fill;
    }

11、el-table 操作

选中行

给 el-table 定义 ref="menuTable" :data="menuList"

this.$refs.menuTable.toggleRowSelection(this.menuList[0]);

列内容过长隐藏

el-table-column show-overflow-tooltip 当内容过长被隐藏时显示 true/false
例::show-overflow-tooltip="true"
el-table tooltip-effect 控制颜色 dark/light
例:tooltip-effect="light"

12、el-tree 操作

a.设置树选中行的颜色

.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
    background-color: #a6d1ff;
}

b.选中树结点

// 通过 key 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性
// (key) 待被选节点的 key,若为 null 则取消当前高亮的节点
this.$refs.myTree.setCurrentKey(myKey);

// 通过 node 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性
this.$refs.myTree.setCurrentNode(myNode);

选中单个

this.$refs['catalogTree'].setChecked(catalogId, true, false);

清空选中

this.$refs['catalogTree'].setCheckedKeys([])

13、谷歌浏览器 input 自动填充颜色改变或透明

设置黄色背景变成白色背景

input:-webkit-autofill {
 box-shadow: 0 0 0px 1000px white inset !important;
}  
input:-webkit-autofill:focus {
 box-shadow: 0 0 0px 1000px white inset !important;
} 

设置透明:

input:-internal-autofill-previewed,
input:-internal-autofill-selected {
    -webkit-text-fill-color: #FFFFFF !important;
    transition: background-color 5000s ease-in-out 0s !important;
}

不要混合用、亲测有效

14、可输入可选择级联器组件

<template>
    <el-cascader filterable ref="cstmInputDepartmentDascader" :options="departmentCascader" v-model="departmentValue"
                 :props="{ checkStrictly: true }"
                 :show-all-levels="showAllLevels"
                 :debounce="500" style=" 100%"
                 :before-filter="beforeFilterDepartment"
                 @blur="blurDepartment"
                 @focus="focusDepartment"
                 @change="changeDepartment"
    ></el-cascader>
</template>

<script>
    import {deepClone} from '@/util/util';
    import {getCascaderAttach} from '@/api/admin/department';

    export default {
        name: "input-department-cascader",
        props: {
            value: {},
            showAllLevels: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                departmentList: [],
                departmentCascader: [],
                departmentCascaderBack: [],
                departmentCascaderLength: undefined,
                departmentValue:[],
                inputDepartmentName: undefined,
                increment: 1
            }
        },
        created() {
            this.getDepartmentCascader();
        },
        mounted() {
            this.init();
        },
        methods: {
            getDepartmentCascader() {
                getCascaderAttach().then(response => {
                    // 部门列表数据 id,parentId,treePosition, 根节点parentId是0,treePosition没有
                    this.departmentList = response.data.attachData;
                    // 部门级联数据 label,value,children,disabled
                    this.departmentCascader = response.data.cascaderData;
                    this.departmentCascaderLength = this.departmentCascader.length;
                    // 部门级联数据备份
                    this.departmentCascaderBack = deepClone(this.departmentCascader);
                    this.init();
                })
            },
            init() {
                if (!this.value) return;
                let value = [];
                let list = deepClone(this.departmentCascaderBack);
                let department = this.getDepartmentById(this.value);
                // 没有找到就认为是输入的数据
                if (!department) {
                    list.push(this.getItem(this.value));
                    value.push(this.value);
                } else {
                    if (department.treePosition) {
                        value = department.treePosition.substr(1).split('&');
                    }
                    value.push(this.value);
                }
                this.departmentCascader = list;
                this.departmentValue = value;
            },
            getDepartmentById(id) {
                let department = undefined;
                if (this.departmentList && id) {
                    for (let item of this.departmentList) {
                        if (id === item.id) {
                            department = deepClone(item);
                            break;
                        }
                    }
                }
                return department;
            },
            getItem(name) {
                return {
                    value: name,
                    label: name,
                    children: undefined,
                    disabled: false
                }
            },
            beforeFilterDepartment: function(value) {
                this.inputDepartmentName = value;
                return false;
            },
            blurDepartment() {
                if (!this.inputDepartmentName) return;
                this.$set(this.departmentCascader, this.departmentCascaderLength, this.getItem(this.inputDepartmentName));
                this.departmentValue = [this.inputDepartmentName];
                this.inputDepartmentName = undefined;
                this.changeDepartment(this.departmentValue);
            },
            focusDepartment() {
                this.$refs.cstmInputDepartmentDascader.$refs.input.$refs.input.select();
            },
            changeDepartment(v) {
                if (v && v.length > 0) {
                    this.$emit('input', v[v.length - 1]);
                } else {
                    this.$emit('input', '');
                }
            }
        }
    }
</script>

<style scoped>

</style>

15、展开el-tree指定的结点

this.$refs['catalogTree'].store.currentNode.expanded = true
this.$refs['catalogTree'].store.nodesMap["id"].expanded = true

16、日期、时间、时间戳控件

<!-- 日期 -->
<el-date-picker v-model.trim="mydate"
                value-format="yyyy-MM-dd"
                format="yyyy-MM-dd"
                type="date"
                placeholder="请选择日期"></el-date-picker>

<!-- 时间 -->
<el-time-picker v-model.trim="mytime"
                value-format="HH:mm:ss"
                format="HH:mm:ss"
                placeholder="请选择时间"></el-time-picker>

<!-- 时间戳 -->
<el-date-picker v-model.trim="mydatetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                format="yyyy-MM-dd HH:mm:ss"
                type="datetime"
                placeholder="请选择时间戳"></el-date-picker>

value-format 控制值的格式,format 控制显示的格式,这两个可以不同,根据具体情况选择控制

 17、表格树 el-table-tree-column 问题

<el-table-tree-column 
    fixed                 是否固定
    :expand-all="false"   是否展开
    :indent-size="20"     子层相对于父层的缩进px
    child-key="children"  子层级数据(数组形式)
    levelKey="level"      层级1,2,3代表第几层
    treeKey="value"       当前层级的ID, 子层级的parentKey与父层级treeKey一致
    parentKey="parentId"  父层级的ID, 与父层级treeKey一致
    prop="label"          显示的属性
    label="名称"           表头文字
>

注意:treeKey可以不指定,默认使用对象的ID属性,若没有ID属性则需要使用treeKey明确指定属性,否则会出现各个层级被同时操作的问题(都展开或关闭)。levelKey在没有时子层和父层之间没有缩进。

18、el-dialog弹出框的body设置高度

问题代码

<el-dialog ref="taskDialog" title="标题" :fullscreen="true"
           :visible.sync="dialogTaskVisible"
           :close-on-click-modal="closeOnClickModal"
           @close="closeTaskDialog">
    <iframe ref="taskIframe" :style="{height: iframeHeight}"
            :src="this.currentTask.url"
            class="iframe" @load="iframeLoad"></iframe>
    <div slot="footer" class="dialog-footer">
        <el-button @click="closeTaskDialog">取消</el-button>
    </div>
</el-dialog>

iframe 的 style 设置 height:100% 没有撑开 el-dialog__body 部分

解决方式是给 iframe 动态设置具体的高

定义 iframeHeight,给 el-dialog 定义 ref="taskDialog", 绑定 @load="iframeLoad" 加载完成事件,在事件方法中计算高度并设置,

监听窗口大小变化,在事件方法中计算高度并设置

data() {
    return {
        screenWidth: document.documentElement.clientWidth,
        screenHeight: document.documentElement.clientHeight,
        iframeHeight: '100%'
    };
},
watch:{
    'screenWidth':function(val){ //监听屏幕宽度变化
    },
    'screenHeight':function(val){ //监听屏幕高度变化
        this.iframeLoad();
    }
},
mounted() {
    var _this = this;
    window.onresize = function(){ // 定义窗口大小变更通知事件
        _this.screenWidth = document.documentElement.clientWidth; //窗口宽度
        _this.screenHeight = document.documentElement.clientHeight; //窗口高度
    };
},
methods: {
    iframeLoad() {
        this.$nextTick(()=>{
            this.iframeHeight = this.$refs['taskDialog'].$el.offsetHeight - 130 + 'px'; // 用 dialog 总高减去 头部和底部的高,总宽 offsetWidth
        })
    },
}

-

原文地址:https://www.cnblogs.com/yangchongxing/p/10750994.html