-
Notifications
You must be signed in to change notification settings - Fork 0
ElementUI Skills&Tips
- Vue2.6要用TypeScript需要使用vue-class-component/vue-property-decorator,使用Vuex的话要用vuex-module-decorators
- 参考官网
- 基本是对组件的使用中遇到的坑
- :label-position="labelPosition" label标签对齐方式
- :model="formLabelProps" form全部form-item的数据可以通过一个data绑定到form上,form-item绑定对应的prop,其中的输入框上绑定对应的v-model='formLabelProps.xx'即可
- :rules 校验规则:同antd,都用了这个,区别在于antd中的callback要求返回一个Promise,重点在于检验后对于不符合规则的条目进行自定义提示,例:复制自官网:
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
var checkAge = (rule, value, callback) => {
if (!value) {
return callback(new Error('年龄不能为空'));
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('请输入数字值'));
} else {
if (value < 18) {
callback(new Error('必须年满18岁'));
} else {
callback();
}
}
}, 1000);
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
ruleForm: {
pass: '',
checkPass: '',
age: ''
},
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>-
:label-suffix 表单域标签的后缀
-
:hide-required-asterisk 是否显示必填字段的标签旁边的红色星号
-
:show-message 是否显示校验错误信息
-
resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
-
校验失败,自动滚动到失败的那一项:
// submit表单时,进行校验
submitForm() {
// 通过ref拿到el-form的DOM
this.formRef.validate(async (valid: boolean, object: ValidObject) => {
if (valid) {// do sth ...}
else { scrollView(object); }
}
}
// 滚动方法
scrollView(object: ValidObject) {
for (let i = 0; i < Object.keys(object).length; i++) {
const key = Object.keys(object)[i];
const dom: App = this.$refs[key] as App; // Vue+TS 用法很怪...有些地方感觉用decorator并不方便
// 滚动到指定节点
dom.$el.scrollIntoView({
// 值有start,center,end,nearest,当前显示在视图区域中间
block: 'start',
// 值有auto,instant,smooth,缓动动画(当前是慢速的)
behavior: 'smooth',
});
// 只需要检测一项跳出循环
break;
}
} <el-upload
ref="upload"
:file-list="fileList"
:on-success="uploadFileSuccess"
:before-upload="beforeUploadFile"
:on-remove="handleRemove"
:auto-upload="true"
:on-exceed="handleExceed"
:on-preview="handlePreview"
:limit="10"
multiple
action
:http-request="handleUploadFile"
>
<el-button
size="small"
slot="trigger"
:disabled="uploadable"
v-if="!uploadable"
type="primary"
icon="el-icon-upload"
>上传附件</el-button
>
<el-button
size="small"
slot="tip"
disabled
v-if="uploadable"
type="primary"
icon="el-icon-upload"
>上传附件</el-button
>
<div slot="tip" class="el-upload__tip">
附件单个大小不可超过20MB
</div>
</el-upload>-
action 必选参数,上传的地址
-
multiple 是否支持多选文件
-
drag 是否启用拖拽上传
-
show-file-list是否显示已上传文件列表
-
on-preview 点击文件列表中已上传的文件时的钩子,可以在此处进行文件上传后的预览或下载等动作
-
on-remove 文件列表移除文件时的钩子
-
on-success 文件上传成功时的钩子
-
before-upload 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
-
before-remove 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。
-
file-list 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
-
auto-upload 是否在选取文件后立即进行上传
-
list-type 文件列表的类型 text/picture/picture-card
-
http-request 覆盖默认的上传行为,可以自定义上传的实现
-
on-exceed 文件超出个数限制时的钩子
-
limit 最大允许上传个数
-
tips: 上传按钮只能用disable修改样式,但是依然可以点击,所以设置两个按钮,配合slot="tip"实现禁用上传功能
-
在before-upload中校验文件格式、大小等,on-success之中可以得到上传后的所有文件列表,on-remove之中得到移除某个文件之后的剩下的全部文件
- 坑:destroy-on-close 关闭时销毁 Dialog 中的元素,不可用!!!也就是说dialog关闭之后不会销毁,而会保留上一次的内容。
- modal-append-to-body 遮罩层是否插入至 body 元素上,若为 false,则遮罩层会插入至 Dialog 的父元素上
- modal 是否需要遮罩层
- width Dialog 的宽度,默认50%,width="800px",注意要加上单位!!!
- visible 是否显示 Dialog,支持 .sync 修饰符
- lock-scroll 是否在 Dialog 出现时将 body 滚动锁定
- before-close 关闭前的回调,会暂停 Dialog 的关闭 function(done),done 用于关闭 Dialog 可能可以用于解决上面的不销毁组件的坑……
- 自定义分页样式
<template>
<div class="my-pagination">
<el-pagination
:current-page.sync="currentPageSync"
:layout="layout"
:total="total"
:page-size="pageSize"
@current-change="handleCurrentChange"
>
<el-dropdown placement="bottom" @command="handleSizeChange">
<div>
<span class="pagination-text left">每页</span>
<el-button class="dropdowm-page__button">
<span>{{ pageSize }}<i class="el-icon-arrow-down el-icon--right"></i></span>
</el-button>
<span class="pagination-text right">条</span>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="p in pageSizes" :key="p" :command="p">{{ p }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-pagination>
</div>
</template>
<script lang="ts">
/**
* 自定义分页组件
* 默认参数
* layout: slot, prev, pager, next
* total: 0
* pageSize: 10
* currentPage: 1
* */
import { Component, Prop, PropSync, Emit, Vue } from 'vue-property-decorator';
@Component
export default class App extends Vue {
@Prop({ default: 0 }) total!: number;
@Prop({ default: 10 }) pageSize!: number;
@Prop({ default: (layout: string) => `slot, ${layout || 'prev, pager, next'}` }) layout!: string;
@Prop({ default: () => [10, 20, 50, 100, 200] }) pageSizes!: Array<number>;
// PropSync,接收prop:currentPage,生成一个新的计算属性:currentPageSync,之后再同步给自身
@PropSync('currentPage', { default: 1, type: Number }) currentPageSync!: number;
// 下面两个空函数只是用于emit到父组件,触发对应的事件,不需要传递值
@Emit('size-change')
handleSizeChange(pageSize: number) {}
@Emit('current-change')
handleCurrentChange(currentPage: number) {}
}
</script>
<style lang="less" scoped>
.my-pagination ::v-deep .el-pagination {
.pagination-text {
width: 30px;
height: 30px;
font-size: 14px;
color: #00ee14;
letter-spacing: 0;
line-height: 30px;
font-weight: 400;
&.right {
text-align: left;
padding-left: 8px;
}
&.left {
text-align: right;
padding-right: 8px;
}
}
.dropdowm-page__button {
width: 60px;
height: 28px;
position: relative;
text-align: left;
line-height: 24px;
padding: 0 10px 0 12px;
background: #fff;
border: 1px solid grey;
color: balck;
}
.el-icon-arrow-down.el-icon--right {
position: absolute;
right: 6px;
top: 6px;
}
}
</style>
// 使用
<am-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="current"
:page-sizes="[10, 20, 50]"
:page-size="pageSize"
layout="slot, prev, pager, next"
:total="total"
></am-pagination>
- @PropSync装饰器与@prop用法类似,二者的区别在于:
- @PropSync 装饰器接收两个参数:
- propName: string 表示父组件传递过来的属性名;
- options: Constructor | Constructor[] | PropOptions 与@Prop的第一个参数一致;
- @PropSync 会生成一个新的计算属性