iview学习地址:https://www.iviewui.com/
1.iview了解;
开发过项目后台管理系统的人都知道,很多数据都是呈一个列表的形式展现给管理员,或者以各种图展现。就比如,用户数据和一些优惠券信息等都需要以一个列表的形式展现给管理员;再就是一些用户的消费情况会以曲线图、折线图、柱状图等展示给管理员,用于用户分析,方便推荐。而在开发后台管理系统中,基本上都是很多前端人员参与开发,导致列表样式和布局都不一样,所以开发后台管理系统很需要一个统一的风格的表格,也需要一个合格的UI设计图纸才行。故为了节约开发成本,又能实现统一风格,选择iview是一个不错的选择,而且它是一套基于 Vue.js 的高质量 UI 组件库!
2.iview引用;
1)首先,在你的vue项目中安装iview依赖;
在你的命令窗口输入:npm install iview --save(记得要先进去你的文件所在目录)
或者先在package.json文件里的"dependencies"下写下:"iview": "^3.0.0",
然后再在命令窗口输入:npm install
均可。
2)安装之后,然后就在vue项目的入口文件里全局引入它;
即在main.js文件的头部写下:
import iView from 'iview';
3)由于通过npm下载的iview插件会自带一个样式文件,即iview.css,这个文件也需要导入进去;
即在main.js文件的头部写下:
import 'iview/dist/styles/iview.css';
3.效果;
这里先把效果图展示出来,让大家有个大概的认识:
4.后台返回的数据格式;
如下图:
5.使用;
知道后台返回的数据格式之后便可很清楚的知道该怎么使用iview了。
HTML部分:
<i-table border :content="self" :columns="columns" :data="giftCardsList"></i-table>
在显示列表的文件里引入<i-table>标签即可。
这里我需要解释下它的一些属性作用及一些值:
首先来看几个最常用的
1)content:设置单元格内渲染自定义组件时的上下文。比如父级是 $parent,根组件是 $root,当 i-table
作为一个 slot 封装在其它组件里时,会很有用;这里我用的是self,在data中我return了一个默认值,就是self: this。意思就是把this指向的对象复制一份给self,这样可避免this指向问题出现;
2)columns:表格列的配置描述,下面给出JS代码便可理解;
3)data:显示的结构化数据;
4)下面附上iTable的一些API图:
JS代码:
export default {
data() {
return {
giftCardsList: [],
self: this,
columns:[
{
title:'Id',
type: 'index',
width: 60,
align: 'center'
},
{
title: '优惠券名称',
key: 'name',
align: 'center'
},
{
title: '类型',
key: 'extent',
align: 'center'
},
{
title: '兑换内容',
key: 'days',
align: 'center'
},
{
title: '有效期',
key:'start_at',
align: 'center',
},
{
title:'已使用',
key:"use",
align: 'center',
},
{
title:"剩余库存",
key:"last",
align: 'center'
},
{
title:"使用率",
key:"use_tate",
align: 'center'
},
{
title:"状态",
key:"status",
align: 'center'
},
{
title:"操作",
key:"actor",
align:'center',
render: (h, params) => {
if(this.giftCardsList[params.index].status === '进行中'){
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
style: {
marginRight: '5px'
},
on: {
click: () => {
this.$router.push({ path: '../marketing_manage/add_gift_card?gcid=' + this.giftCardsList[params.index].gcid});
}
}
}, '编辑'),
h('Button', {
props: {
type: 'error',
size: 'small'
},
on: {
click: () => {
this.popupIsShow = true;
this.gcid = this.giftCardsList[params.index].gcid;
}
}
}, '使失效')
]);
}else{
return h('div', [
h('Button', {
props: {
type: 'primary',
size: 'small'
},
on: {
click: () => {
this.$router.push({ path: '../marketing_manage/gift_card_warehouse?gcid=' + this.giftCardsList[params.index].gcid});
}
}
}, '码库')
]);
}
}
}
],
}
},
下面是有关于columns的一些介绍:
5)博主这里已经将iview关于列表的大致使用已经陈述清楚了,也公布了后台返回的数据格式,只要将对应的字段填充在columns中就可以实现了。另外的一些点击事件,也可以查下官网里的介绍 :http://v1.iviewui.com/components/table
6.补充;
引用iview插件之后,会对原来之前写的一些功能带来一些冲击,但是修复起来并不算困难。
这个是之前我写的导出列表功能实现的路径:https://blog.csdn.net/Charles_Tian/article/details/81146932
现在用上了iview,所以之前写的意味着要废弃了,下面来看看引入iview之后该怎么实现导出数据:
1)需要在Table的第一列新增一个复选框,用于选中项,官网给出的介绍如下:
由于新增的复选框是在data里面完成的,如下代码:
columns:[
{
type: 'selection',
width: 50,
align: 'center',
},
{
title:'id',
key: 'id',
width: 100,
align: 'center',
},
{
title: '兑换码',
key: 'gccid',
align: 'center'
},
{
title: '会费名称',
key: 'name',
align: 'center'
},
{
title: '类型',
key: 'extent',
align: 'center'
},
{
title: '有效期',
key:'start_at',
align: 'center',
},
{
title:'使用人',
key:"username",
align: 'center',
},
{
title:"兑换时间",
key:"use_at",
align: 'center'
},
{
title:"状态",
key:"status",
align: 'center'
}
],
很明显的看出,新增了三行代码,即:
{
type: 'selection',
width: 50,
align: 'center',
},
新增完之后,看下效果图:
2)说明下该怎么使用这三个事件;
刚开始始终不知道到底该怎么用,不知道选中事件应该添加到哪里,后来慢慢尝试发现,这三个事件之一是要绑定要<i-table>组件上的,如下HTML代码:
<i-table height="660" border :content="self" :columns="columns" :data="warehouseList" ref="table" @on-selection-change="gccidArr"></i-table>
由于项目支持部分数据导出,所以最终选择了@on-select-change事件
3)官网里又介绍,触发该事件之后,返回值为selection,那么这个selection的值我们到底该怎么用呢?
由于我们创建了一个名为gccidArr的方法名,那么我们需要在methods里面定义它,如下代码:
gccidArr(selection){
this.selection = selection;
},
就这么简单就获取到了你选中的数据了。注意:这里的数据是一行的数据,不是某一个具体的值,而且selection的数据类型是数组。如果想要获取,可以在columns里面新增一个render方法,或者新建一个空的数组dataArr,利用this.selection.forEach(ele => {dataArr.push(ele.id)})即可,也就是将获取到的每条数据里的某一个值(比如id,title等)存进一个新建的数组中。
4)我们可以验证下,如下图:
我分别选中三个,每次都会打印出selection的值,所以我们的应用方向是正确的。
5)选中之后并保存在内存中,但是我们到底要怎么导出呢?而导出的数据恰好是我们所选中的呢?
首先肯定要新增一个导出的按钮,如HTML代码:
<i-table height="660" border :content="self" :columns="columns" :data="warehouseList" ref="table" @on-selection-change="gccidArr"></i-table>
<i-button style="margin-top:10px" type="primary" size="large" @click="exportData()"><Icon type="ios-download-outline"></Icon> 导出数据 </i-button>
这个i-button也是iview应用之一,大家可自行官网了解。
同样的,要在methods里定义一个名为exportData的方法,导出数据JS代码如下:
exportData: function(){
let self = this;
this.$refs.table.exportCsv({
filename: '码库',
original: false,
columns: self.columns,
data: self.selection
});
},
下面是exportCsv的用法和属性介绍:
由于我们要导出的是自定义数据,所以original要为false,另外columns和data必须同时定义。
执行操作之后,我们便可以得到一个名为码库的csv文件,里面就是我们选中的数据。
6)可能会有童鞋会问,要是有些数据是不可选中的呢?意思就是我要想某些行数据的前面没有复选框,那该怎么实现?
这个问题其实也好解决,只需要将前面的复选框失效就好了,就是不能点击的状态,那么用iview怎么实现呢?
大家可看官网里这样的介绍:
意思就是在data对象(就是后台返回的数据,也即应用table里的数据,也就是上文在HTML代码里的:data="warehouseList"里 的warehouseList)里面添加一个属性_disabled,且它的值为true即可,看JS代码:
handleDeadline: function(warehouseList){
warehouseList.forEach(element => {
if(element.status == '0'){
element['_disabled'] = true;
}
});
return warehouseList;
},
然后调用这个函数即可,看效果图:
明显看到复选框为暗色了,我也测试了,不可点击,所以selection里面也没值,完美解决~
------------------------------------------------------------------------------------------------------------------------------------------------------------------
2018.11.08
今天开发时遇到了一个有趣的现象,是关于利用iview插件开发的问题
就是要达到这种效果,点击图片的时候,会显示正常的图片大小,利用的是iview的Modal标签,出现的问题是这样的,<Modal width="?">其width属性不能给固定的值,忽略这个属性的话,会默认为100%,也就是继承body的宽度,这很显然不行,那么到底该怎么办呢?
网上查了下js用什么方法可以获取图片的宽高, 一个是现代浏览器支持的H5用法,就是图片对象有一个方法naturalWidth()和naturalHeight()可获取图片的宽高,IE的旧浏览器用var imgObj = new Image(),然后用imgObj.width()和imgObj.height()方法获取宽高。
现在我们主要使用的是现代浏览器,所以这里我用H5的方法,但是这又会出现一个问题,就是用这种方法做后,会发现你有时可以取得 img 的 width、height ,但有时会是个 0,0肯定不是我们想要的,但是又要解决这个问题,又该怎么办?出现这种情况的原因又是什么呢?
原因是这样的:在某些电脑上的谷歌浏览器和IE11浏览器上,以上代码(imgObj.naturalWidth();imgObj.naturalHeight())工作正常。但是在某些电脑上会报出和火狐在第一次打开时却报出宽高值均为0
。如果按F5刷新页面,又能正确获取宽高值了。按 Ctrl+F5 强制刷新(忽略缓存)的话,仍能复现这个问题。
这是因为火狐对于JS异步运行非常快。当载入image.src = "apple.jpg";
时,火狐已经开始运行imgObj.naturalWidth();imgObj.naturalHeight();这两行代码之后的代码了。而且这与DOM无关,完全是javascript和浏览器的问题(或者可以认为是异步获取)。
所以,为了能正确获取到图片的原始尺寸,又要解决会获取"0"的问题,这里我们可以用事件机制解决,即用setTimeout去将要获取图片尺寸的代码延迟执行即可解决(也就是模拟异步)。
但是需要注意的是,setTimeout会改变this的指向(也就是作用域的问题),所以可以用箭头函数或者声明var that = this;解决即可。
代码如下:
HTML:
<Modal
v-model="hImgModal"
:width="hImgWidth"
@on-cancel="hImgModal=false"
:closable="false">
<div slot="footer"></div>
<img :src=hIma ref="hImg">
</Modal>
JS:
data() {
return {
hImgModal:false,//横图
hImgWidth:'',//横图宽
columns: [//这是iview的用法,key表示的是,每个类型的字段
{
type: 'selection',
width: 60,
align: 'center'
},
{
title: '影片名称',
key: 'name_chs',
align: 'center'
},
{
title: '海报横图',
key: 'hcover',
align: 'center',
render:(h,params)=>{
let item = this.filmList[params.index]//filmList为后台返回的影视数据
return h('div',[
h('Img',{
attrs:{
src:item.hcover,
},
style:{
width: '80px',
height: '45px',
margin:'5px',
cursor:'pointer'
},
on:{
click:()=>{
let that = this;
this.hImgModal=true;
this.hIma = item.hcover;
setTimeout(function(){
that.hImgWidth = that.$refs.hImg.naturalWidth + 30;
},0)
}
}
})
])
}
},
],
}
},
经个人亲测,效果完美~
------------------------------------------------------------------------------------------------------------------------------------------------------------------
2018.11.28更新
在使用iview开发的时候又遇到了一个问题,这个问题解决的思路其实我想到了,但是突然之间忘记该怎么去实现了,还需进一步学习啊~~~
问题:想在表格的一个列中展示多个(不是固定值)button,每个button都会绑定一个事件。
想要的效果:
在上述分享中我们知道了,怎么在操作一列去添加各种操作button,且这种button的名字是根据如下代码进行渲染的:
// h函数里的第一个参数表示的是组件的名称,第二参数是一个对象,这个对象包括属性,样式和事件等,第三个参数是渲染到前端的button的名字。
// 第一个参数和第三个参数的数据类型是字符串,且第三个参数非必须
h('Button', {props:{}, style:{}, on:{}}, '编辑')
而现在的难点是,我的子分类的一列中,子分类的名称的数量是不固定的,所以不好再用之前的固定方法了。
我们也很容易想到用数组遍历的方式,遍历子分类这个数组,便可以得到每个子分类具体的名称,并绑定上事件。
那么到底该怎么去遍历呢?
不知道大家有没有仔细分析过,render这个方法可以覆盖默认的显示,也就是说,不加render方法的话,那么每一列展示下来的数据就是根据字段key的值来渲染的(这里不懂的看上面的介绍),而加了之后,渲染出来的就是render方法最终return出来的。而根据iview的特点知道,return出来的是一个函数(也可以称为方法),也就是h()函数,该函数的特点在上面的代码注释中解释过了,这里不再赘述。
所以,这里的解决方法是这样的:
首先,声明一个变量let option = h('div', []);
然后遍历子分类这个数组并给每个元素做如期望那样的处理;
随后再利用option.children.push()的方法,把每个处理后的子分类添加进去;
最终将变量option,return出去。
完整代码:
{
title:'子分类',
align: 'center',
render: (h, params) => {
let item = this.tagslist[params.index];//tagslist是数据列表,每个项目中都包含一个子分类数组
let option = h('div',[]);
item.sub_tags.forEach((ele,idx) => {//sub_tags才是子分类数组
let subOptions = h('Button', {
props: {
type: 'text',
size: 'small',
},
style: {
color: '#1255e2',
margin: '5px',
border: '1px solid #1255e2'
},
on: {
click: () => {
this.pop_remove_subtag(item, ele);//参数可根据实际项目需求取
},
},
}, ele.name_chs+' | X');
option.children.push(subOptions)
})
return option;
}
上面有个瑕疵,就是利用了字符串' | X'来代替了'关闭'图标,其实在iview中可利用Tag标签来实现的,但是iview有个bug,就是它的关闭事件在刚才我们的这个案例上触发不了。
<template>
<Tag v-for="item in count" :key="item" :name="item" closable @on-close="handleClose2">标签{{ item + 1 }}</Tag>
</template>
即上面的on-close事件
比如,将代码改成这样:
{
title:'子分类',
align: 'center',
render: (h, params) => {
let item = this.tagslist[params.index];
let option = h('div',[]);
item.sub_tags.forEach((ele,idx) => {
let subOptions = h('Tag', {
props: {
color: 'default',
closable: true
},
on: {
click: () => {
this.pop_remove_subtag(item, ele);
},
close: () => {
this.pop_remove_subtag(item, ele);
},
onClose: () => {
this.pop_remove_subtag(item, ele);
},
},
}, ele.name_chs+' | X');
option.children.push(subOptions)
})
return option;
}
不管是click,还是close,还是onClose都触发不了里面的函数,根本就走不进去!
博主猜测,可能的原因是 iview封装的on-close事件存在问题(只是猜测啊!个人观点)