iView的使用

官网

iView4

基于Vue2的最新版本

http://v4.iviewui.com/docs/introduce

安装

1
2
npm install view-design --save
npm install vue-cli-plugin-iview --save-dev

使用

1
2
3
import ViewUI from "view-design";
import "view-design/dist/styles/iview.css";
Vue.use(ViewUI);

图标

http://v4.iviewui.com/components/icon

Row/Col

1
2
3
4
5
6
<Row type="flex" justify="center" align="middle">
<Col span="4"></Col>
<Col span="4"></Col>
<Col span="4"></Col>
<Col span="4"></Col>
</Row>

Flex

1
2
3
4
<Row>
<Col flex="100px">100px</Col>
<Col flex="auto"></Col>
</Row>

Table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<template>
<div>
<Table border :columns="table_header" :data="table_data">
<template slot-scope="{ row }" slot="name">
<strong>{{ row.name }}</strong>
</template>
<template slot-scope="{ row, index }" slot="action">
<Button
type="primary"
size="small"
style="margin-right: 5px"
@click="show(index)"
>查看</Button
>
<Button type="error" size="small" @click="remove(index)">删除</Button>
</template>
</Table>
</div>
</template>

<script>
export default {
name: "assess_detail",
data: function() {
return {
table_header: [
{
title: "Name",
slot: "name"
},
{
title: "Age",
key: "age"
},
{
title: "Address",
key: "address"
},
{
title: "Action",
slot: "action",
width: 150,
align: "center"
}
],
table_data: [
{
name: "John Brown",
age: 18,
address: "New York No. 1 Lake Park"
},
{
name: "Jim Green",
age: 24,
address: "London No. 1 Lake Park"
},
{
name: "Joe Black",
age: 30,
address: "Sydney No. 1 Lake Park"
},
{
name: "Jon Snow",
age: 26,
address: "Ottawa No. 2 Lake Park"
}
]
};
},
methods: {
show(index) {
this.$Modal.info({
title: "User Info",
content: `Name:${this.table_data[index].name}<br>Age:${this.table_data[index].age}<br>Address:${this.table_data[index].address}`
});
},
remove(index) {
this.table_data.splice(index, 1);
}
}
};
</script>

Page(分页)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<template>
<div>
<Page
:current="mPageModel.current"
:page-size="mPageModel.page_size"
:page-size-opts="mPageModel.page_size_opts"
:total="mPageModel.total"
@on-change="pageChange"
@on-page-size-change="pageSizeChange"
prev-text="上一页"
next-text="下一页"
show-elevator
show-sizer
show-total
/>
</div>
</template>

<script>
export default {
name: "assess_detail",
data: function() {
return {
mPageModel: {
current: 1,
page_size: 10,
page_size_opts: [10, 20, 30],
total: 100
}
};
},
methods: {
pageChange(page) {
this.mPageModel.current = page;
},
pageSizeChange(pageSize) {
this.mPageModel.page_size = pageSize;
},
}
};
</script>

弹窗

基本弹窗

1
2
3
4
5
6
7
8
9
<Modal
v-model="show_add_dialog"
width="800"
draggable
sticky
scrollable
:mask="true"
title="我是标题">
</Modal>

自定义Footer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<Modal
v-model="show_pwd_dialog"
width="520"
draggable
sticky
scrollable
:mask="true"
title="修改密码"
>
<Form
ref="myPwdForm"
:model="pwdForm"
:label-width="80"
:rules="ruleValidate"
>
<FormItem label="原密码" prop="pwdold">
<Input v-model="pwdForm.pwdold" placeholder="请输入原密码"></Input>
</FormItem>
<FormItem label="新密码" prop="pwdnew">
<Input v-model="pwdForm.pwdnew" placeholder="请输入新密码"></Input>
</FormItem>
<FormItem label="新密码" prop="pwdnew2">
<Input
v-model="pwdForm.pwdnew2"
placeholder="请再次输入新密码"
></Input>
</FormItem>
</Form>
<div slot="footer">
<Row>
<Col flex="auto"></Col>
<Col>
<Button @click="show_pwd_dialog = false">取消</Button>
<Button type="primary" @click="changeAction">确定</Button>
</Col>
</Row>
</div>
</Modal>

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
data() {
return {
show_pwd_dialog: false,
pwdForm: {
pwdold: "",
pwdnew: "",
pwdnew2: "",
},
ruleValidate: {
pwdold: [{ required: true, message: "请输入原密码", trigger: "blur" }],
pwdnew: [{ required: true, message: "请输入新密码", trigger: "blur" }],
pwdnew2: [
{ required: true, message: "请再次输入新密码", trigger: "blur" },
],
},
};
},
methods: {
async changeAction() {
let valiResult = await this.$refs["myPwdForm"].validate();
console.info(valiResult);
},
},
};

重置表单

1
this.$refs["myPwdForm"].resetFields();

抽屉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<template>
<div>
<Drawer
title="选择"
v-model="showDrawer"
width="720"
:mask-closable="false"
:styles="drawerDtyles"
>

<div class="my-drawer-footer">
<Button style="margin-right: 8px" @click="showDrawer = false">取消</Button>
<Button type="primary" @click="showDrawer = false">提交</Button>
</div>
</Drawer>
</div>
</template>
<script>
export default {
data () {
return {
showDrawer: true,
drawerDtyles: {
height: 'calc(100% - 55px)',
overflow: 'auto',
paddingBottom: '53px',
position: 'static'
},
}
}
}
</script>
<style>
.my-drawer-footer{
width: 100%;
position: absolute;
bottom: 0;
left: 0;
border-top: 1px solid #e8e8e8;
padding: 10px 16px;
text-align: right;
background: #fff;
}
</style>

提示信息

1
2
3
4
this.$Message.info(res.msg);
this.$Message.warning(res.msg);
this.$Message.success(res.msg);
this.$Message.error(res.msg);

加载中

加载中

1
2
3
4
const msg = this.$Message.loading({
content: "加载中...",
duration: 0,
});

取消加载中

1
setTimeout(msg, 3000);

或者用全局销毁

1
this.$Message.destroy();

在接口请求拦截或者其他不在vue内的,可以如下调用

1
2
import { Message } from "view-design";
Message.warning("我是提示内容");

弹窗提示

1
2
3
4
5
import { Modal } from "view-design";
Modal.warning({
title: "我是提示头",
content: "我是提示内容",
});

确定弹窗

1
2
3
4
5
6
7
8
9
10
this.$Modal.confirm({
title: "删除",
content: `<p>确定要删除用户【${row.username}】吗?</p>`,
onOk: () => {
this.$Message.info("确定");
},
onCancel: () => {
this.$Message.info("取消");
},
});

拦截器中退出

main.js

1
2
3
4
5
window.mVue = new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");

接口拦截器中

1
window.mVue.$router.replace("/login");

密码框禁用复制粘贴

1
2
3
4
5
6
<input name="pwd" type="password" id="pwd" 
onpaste="return false"
oncontextmenu="return false"
oncopy="return false"
oncut="return false"
/>

enter事件

1
v-on:keyup.13="loginClick"

表单

基本表单

1
2
3
4
5
6
7
8
9
10
11
<Form :model="addForm" :label-width="80">
<FormItem label="名称">
<Input v-model="addForm.input" placeholder="请输入名称"></Input>
</FormItem>
<FormItem label="类型">
<Select v-model="addForm.select">
<Option value="Hadoop">Hadoop</Option>
<Option value="minio">minio</Option>
</Select>
</FormItem>
</Form>

带验证的表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<template>
<Form ref="addForm" :model="addForm" :rules="ruleValidate" :label-width="80">
<FormItem label="Name" prop="name">
<Input v-model="addForm.name" placeholder="Enter your name"></Input>
</FormItem>
<FormItem label="E-mail" prop="mail">
<Input v-model="addForm.mail" placeholder="Enter your e-mail"></Input>
</FormItem>
<FormItem label="City" prop="city">
<Select v-model="addForm.city" placeholder="Select your city">
<Option value="beijing">New York</Option>
<Option value="shanghai">London</Option>
<Option value="shenzhen">Sydney</Option>
</Select>
</FormItem>
<FormItem label="Date">
<Row>
<Col span="11">
<FormItem prop="date">
<DatePicker type="date" placeholder="Select date" v-model="addForm.date"></DatePicker>
</FormItem>
</Col>
<Col span="2" style="text-align: center">-</Col>
<Col span="11">
<FormItem prop="time">
<TimePicker type="time" placeholder="Select time" v-model="addForm.time"></TimePicker>
</FormItem>
</Col>
</Row>
</FormItem>
<FormItem label="Gender" prop="gender">
<RadioGroup v-model="addForm.gender">
<Radio label="male">Male</Radio>
<Radio label="female">Female</Radio>
</RadioGroup>
</FormItem>
<FormItem label="Hobby" prop="interest">
<CheckboxGroup v-model="addForm.interest">
<Checkbox label="Eat"></Checkbox>
<Checkbox label="Sleep"></Checkbox>
<Checkbox label="Run"></Checkbox>
<Checkbox label="Movie"></Checkbox>
</CheckboxGroup>
</FormItem>
<FormItem label="Desc" prop="desc">
<Input v-model="addForm.desc" type="textarea" :autosize="{minRows: 2,maxRows: 5}" placeholder="Enter something..."></Input>
</FormItem>
<FormItem>
<Button type="primary" @click="handleSubmit('addForm')">Submit</Button>
<Button @click="handleReset()" style="margin-left: 8px">Reset</Button>
</FormItem>
</Form>
</template>
<script>
export default {
data () {
return {
addForm: {
name: '',
mail: '',
city: '',
gender: '',
interest: [],
date: '',
time: '',
desc: ''
},
ruleValidate: {
name: [
{ required: true, message: 'The name cannot be empty', trigger: 'blur' }
],
mail: [
{ required: true, message: 'Mailbox cannot be empty', trigger: 'blur' },
{ type: 'email', message: 'Incorrect email format', trigger: 'blur' }
],
city: [
{ required: true, message: 'Please select the city', trigger: 'change' }
],
gender: [
{ required: true, message: 'Please select gender', trigger: 'change' }
],
interest: [
{ required: true, type: 'array', min: 1, message: 'Choose at least one hobby', trigger: 'change' },
{ type: 'array', max: 2, message: 'Choose two hobbies at best', trigger: 'change' }
],
date: [
{ required: true, type: 'date', message: 'Please select the date', trigger: 'change' }
],
time: [
{ required: true, type: 'string', message: 'Please select time', trigger: 'change' }
],
desc: [
{ required: true, message: 'Please enter a personal introduction', trigger: 'blur' },
{ type: 'string', min: 20, message: 'Introduce no less than 20 words', trigger: 'blur' }
]
}
}
},
methods: {
handleSubmit (name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.$Message.success('Success!');
} else {
this.$Message.error('Fail!');
}
})
},
handleReset () {
this.$refs["addForm"].resetFields();
}
}
}
</script>

给 Form 设置属性 rules,同时给需要验证的 FormItem 设置属性 prop 指向对应字段即可。

表单验证

触发整个表单的的验证

1
2
//设置表单的ref是userForm
this.$refs.userForm.validate();

触发某个字段的验证

1
2
//触发prop为password表单验证
this.$refs.userForm.validateField("name");

重置表单

1
this.$refs["addForm"].resetFields();

弹窗和表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!--添加表单-->
<Modal
v-model="show_add_dialog"
width="520"
draggable
sticky
scrollable
:mask="false"
:title="addOrUpdate === 1 ? '添加用户' : '编辑用户'"
>
<Form :model="addForm" :label-width="80" :rules="ruleValidate" ref="useraddForm">
<FormItem label="用户姓名" prop="rname">
<Input v-model="addForm.rname" placeholder="请输入用户姓名"></Input>
</FormItem>
</Form>

<div slot="footer">
<Row>
<Col flex="auto"></Col>
<Col>
<Button @click="show_add_dialog = false">取消</Button>
<Button type="primary" @click="addAction">确定</Button>
</Col>
</Row>
</div>
</Modal>

标签选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<template>
<div>
<Select
v-model="selectModel"
multiple
filterable
class="m_select2"
:loading="selectLoading"
:remote-method="selectGetList"
:default-label="selectModel"
allow-create
@on-create="selectHandleCreate"
@on-set-default-options="selectSetDefaultOptions"
>
<Option
v-for="(option, index) in selectOptions"
:value="option"
:key="index"
>{{ option }}</Option
>
</Select>
</div>
</template>

<script>
export default {
name: "TagSelect",
data() {
return {
selectLoading: false,
selectOptions: [],
selectModel: ["北京", "上海"],
selectListAll: ["北京", "上海", "深圳", "广州"],
};
},
methods: {
selectGetList(query) {
if (query !== "") {
this.selectLoading = true;
setTimeout(() => {
this.selectLoading = false;
this.selectOptions = this.selectListAll.filter(
(item) => item.indexOf(query) > -1
);
}, 200);
} else {
this.selectOptions = [];
}
},
selectSetDefaultOptions(options) {
this.selectOptions = options.map((item) => {
return item.value;
});
},
selectHandleCreate(str) {
if (this.selectOptions.indexOf(str) === -1) {
this.selectOptions.push(str);
}
},
},
};
</script>

<style scoped></style>

效果

image-20240223170132501

输入框

复合输入框

1
2
3
4
5
6
7
8
9
10
<Input v-model="value12">
<Select v-model="select1" slot="prepend" style="width: 80px">
<Option value="http">http://</Option>
<Option value="https">https://</Option>
</Select>
<Select v-model="select2" slot="append" style="width: 70px">
<Option value="com">.com</Option>
<Option value="org">.org</Option>
</Select>
</Input>

搜索输入框

1
2
3
4
5
6
7
8
<Input
search
@on-search="searchClick"
@on-enter="searchClick"
placeholder="请输入姓名/用户名/手机号模糊查询"
v-model="searchParam"
style="width: 40rem"
/>

数字输入框

方式1

1
2
3
4
5
6
<Input
v-model.number="addForm.categoryorder"
:number="true"
type="number"
placeholder="请输入排序"
></Input>

这种方式有个问题就是可以输入e,导致保存失败。

方式2

这里我们只让输入正整数。

我们自己处理输入的内容,只保留里面的数字。

1
2
3
4
5
6
7
<Input
v-model.number="addForm.categoryorder"
:number="true"
@keyup.native="inputUpNumber"
type="text"
placeholder="请输入排序"
></Input>

这里使用的是text类型,使用number类型输入1e的时候是获取不到内容的。

方法

1
2
3
4
5
6
7
8
9
10
11
12
inputUpNumber(e) {
let value = e.target.value;
let reg = /^[1-9]{1}[0-9]*$/; // 不能以0开头
if (!reg.test(value)) {
let numArr = value.match(/[0-9]+/g);
if (numArr && numArr.length > 0) {
e.target.value = numArr[0];
} else {
e.target.value = "";
}
}
},

下拉菜单

1
2
3
4
5
6
7
<Dropdown @on-click="userMenuClick">
<span class="user_top"><Icon type="ios-contact" />管理员</span>
<DropdownMenu slot="list">
<DropdownItem name="usercenter">个人中心</DropdownItem>
<DropdownItem name="exit" divided>退出</DropdownItem>
</DropdownMenu>
</Dropdown>

JS

1
2
3
4
5
6
7
methods: {
userMenuClick(name) {
if (name === "exit") {
this.$router.replace("/");
}
},
}

左侧菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<template>
<div class="usercenter">
<div class="left_menu">
<Menu
theme="light"
:open-names="['1', '2', '3']"
:active-name="activeMenu"
@on-select="menuSelect"
style="min-height: 100%"
>
<Submenu name="1">
<template slot="title">
<Icon type="ios-paper" />
内容管理
</template>
<MenuItem name="文章管理">文章管理</MenuItem>
<MenuItem name="分类管理">分类管理</MenuItem>
</Submenu>
<Submenu name="2">
<template slot="title">
<Icon type="ios-people" />
用户管理
</template>
<MenuItem name="用户管理">用户管理</MenuItem>
</Submenu>
<Submenu name="3">
<template slot="title">
<Icon type="ios-stats" />
统计分析
</template>
<MenuItem name="贡献分析">贡献分析</MenuItem>
<MenuItem name="使用分析">使用分析</MenuItem>
</Submenu>
</Menu>
</div>

<div class="right_content">
<div class="content_title">{{ activeMenu }}</div>
<div class="content_outer">
<router-view />
</div>
</div>
</div>
</template>

<script>
export default {
name: "UserCenterView",
data() {
return {
activeMenu: "",
};
},
mounted() {
this.activeMenu = "文章管理";
this.loadPage();
},
methods: {
menuSelect(name) {
this.activeMenu = name;
this.loadPage();
},
loadPage() {
let activeMenu = this.activeMenu;
switch (activeMenu) {
case "文章管理":
this.$router.replace({ path: "/home/usercenter/article_manager" });
break;
}
},
},
};
</script>

<style scoped lang="less">
.usercenter {
height: 100%;
display: flex;

.left_menu {
height: 100%;
overflow-y: auto;
background: white;
}

.right_content {
width: 0;
flex: auto;
height: 100%;
overflow-y: auto;
text-align: left;
display: flex;
flex-direction: column;

.content_title {
height: 40px;
display: flex;
align-items: center;
padding-left: 10px;
font-weight: bold;
font-size: 14px;
color: #999;
border-bottom: 1px solid #ddd;
flex: none;
}

.content_outer {
height: 0;
flex: auto;
overflow-y: auto;
padding: 10px;
box-sizing: border-box;
}
}
}
</style>

分割线

1
2
3
<Divider type="vertical" />

<Divider type="horizontal" />