【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
=============================================================
17、表格树 el-table-tree-column 问题
19、el-cascader TypeError: Cannot read property 'level' of null
22、el-checkbox修改绑定值为false后,页面显示选中,但实际为选中
=============================================================
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="width: 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();
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"]);
表单定义 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>
this.$forceUpdate();
在vue中并不是每次数据改变都会触发更新dom,而是将这些操作都缓存在一个队列,在一个事件循环结束之后,刷新队列,统一执行dom更新操作。 而如果想在DOM状态更新后做点什么,则需要用到nextTick。在vue生命周期的created()钩子函数进行的DOM操作要放在Vue.nextTick()的回调函数中,因为created()钩子函数执行的时候DOM并未进行任何渲染,而此时进行DOM操作是徒劳的,所以此处一定要将DOM操作的JS代码放进Vue.nextTick()的回调函数中。
通过下面的方式设置光标
this.$nextTick(() => { this.$refs['viewFocus'].focus(); });
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说明都是数字验证通过
正常:border-color: #dcdfe6;
焦点:border-color: #409EFF;
出错:border-color: #f56c6c;
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; }
直接给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>
给视频指定样式即可
参考文档:https://blog.csdn.net/wuqingyou_w/article/details/51671356
video { width: 100%; height: 100%; object-fit:fill; }
选中行
给 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"
设置 Table 的 lazy 属性为 true 配合加载函数 load 来加载 row 中的 hasChildren = true 行的子节点。即 hasChildren指定那些行要load子节点
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([])
设置黄色背景变成白色背景
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; }
不要混合用、亲测有效
<template> <el-cascader filterable ref="cstmInputDepartmentDascader" :options="departmentCascader" v-model="departmentValue" :props="{ checkStrictly: true }" :show-all-levels="showAllLevels" :debounce="500" style="width: 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>
this.$refs['catalogTree'].store.currentNode.expanded = true this.$refs['catalogTree'].store.nodesMap["id"].expanded = true
<!-- 日期 --> <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在没有时子层和父层之间没有缩进。
问题代码
<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 }) }, }
19、el-cascader TypeError: Cannot read property 'level' of null
给cascader设置一个key,改变类型时也改变key值,key值改变了,cascader就会重新渲染
<el-cascader :key="keyDataList" :options="optionsDataList" ></el-cascader> <el-cascader filterable v-loading="dirLoading" :disabled="!selectedLib" placeholder="请选择目录" v-model="selectedDir" :size="searchSize" :key="dirKey" :options="dirList" :props="{value: 'id', label: 'name', children: 'children', leaf: 'leaf', disabled: 'disabled', checkStrictly: true }" node-key="id" @change="dirChange" clearable></el-cascader> // Data定义 dirKey: 0, dirList: [] // 数据赋值 ++this.dirKey;// 改变key后,再赋值 this.dirList = list;
<el-input type="password" v-model.trim="password" maxlength="20" show-password auto-complete="new-password" placeholder="密码"></el-input>
autocomplete="off" 不起作用,必须使用 auto-complete="new-password"
show-password 显示密码
<el-table ref="monitorRuleTable" :data="monitorRuleList" stripe border highlight-current-row @selection-change="handleMonitorRuleSelectionChange" @select="handleMonitorRuleSelect"> </el-table> handleMonitorRuleSelect(selection, row) { console.log('单行选择'); this.selectedMonitorRuleRows = []; let checked = false; for (let item of selection) { if (item.id === row.id) { checked = true; break; } } if (checked) { this.selectedMonitorRuleRows.push(row); } console.log('选中',this.selectedMonitorRuleRows.length); if (this.monitorRuleList) { for (let rule of this.monitorRuleList) { if (rule.id === row.id) { this.$refs['monitorRuleTable'].toggleRowSelection(rule, checked); } else { this.$refs['monitorRuleTable'].toggleRowSelection(rule, false); } } } }, handleMonitorRuleSelectionChange(selection) { console.log('全选择'); if (this.monitorRuleList) { for (let rule of this.monitorRuleList) { let checked = false; for (let item of this.selectedMonitorRuleRows) { if (rule.id === item.id) { checked = true; break; } } this.$refs['monitorRuleTable'].toggleRowSelection(rule, checked); } } },
清空选择
this.$refs['newsTable'].clearSelection();
<style scoped> /deep/.el-table__header-wrapper .el-checkbox { display:none } </style>
22、el-checkbox修改绑定值为false后,页面显示选中,但实际为选中
这个问题产生的原因:组件中的判断使用的是事件中的状态,所以修改绑定值无法改变实际状态
handleChange(ev) {
if (this.isLimitExceeded) return;
let value;
if (ev.target.checked) {
value = this.trueLabel === undefined ? true : this.trueLabel;
} else {
value = this.falseLabel === undefined ? false : this.falseLabel;
}
this.$emit('change', value, ev);
this.$nextTick(() => {
if (this.isGroup) {
this.dispatch('ElCheckboxGroup', 'change', [this._checkboxGroup.value]);
}
});
}
简单例子:取消选中
<el-checkbox v-model="chkValue"
@change="chkValueChange(v, ev)"></el-checkbox>
chkValueChange(v, ev) {
// 取消选中
this.chkValue = false;
ev.target.checked = false;
}
-
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性