zoukankan      html  css  js  c++  java
  • 记一次开发过程中,iview遇到的一些坑以及解决办法

    写在开头:本次项目采用的是vue2.0+iview3.0,最近公司没啥事,来总结一下开发过程中遇到的问题。

    1、Modal关闭问题

    需求背景:modal框里面是个form表单,点击确定之后,先验证form表单,验证通过则关闭modal框,验证不成功则提示用户,不关闭。

    问题描述:本来刚开始想通过modal框v-model绑定的值(true或false)来进行控制,手动改之后,报错。

    解决办法:

           官方iview的modal组件的api里面有个loading属性,可通过控制loading的值来进行控制modal的显示。

          

           举例说明:

          

         

         注意: refuseLoading刚开始一定要设置为true。

        

       这样的话就可以解决问题了。

       衍生出来的问题:当关闭模态框之后,再次打开时,表单数据没有重置,还是上一次的数据。

       解决办法:this.$refs[name].resetFields();    重置表单数据,在关闭模态框的时候调用这个方法可解决。

    2、同时验证多个表单问题

    需求背景:一个页面有多个表单,提交的时候需要验证多个表单,都验证成功才能进行下一步操作

    解决办法:用一个数组来存放每个表单的验证结果(true验证通过,false验证不通过),最后循环这个数组如果值都为true,说明验证通过。

                   举例说明:页面有3个表单,需要同时验证,主要代码如下:

    <template>
        <div class="hello">
            <Form ref="formValidate1" :model="formValidate1" :rules="ruleValidate">
                <FormItem label="Name" prop="name">
                    <Input v-model="formValidate1.name" placeholder="Enter your name"></Input>
                </FormItem>
            </Form>
            <Form ref="formValidate2" :model="formValidate2" :rules="ruleValidate">
                <FormItem label="Name" prop="name">
                    <Input v-model="formValidate2.name" placeholder="Enter your name"></Input>
                </FormItem>
            </Form>
            <Form ref="formValidate3" :model="formValidate3" :rules="ruleValidate">
                <FormItem label="Name" prop="name">
                    <Input v-model="formValidate3.name" placeholder="Enter your name"></Input>
                </FormItem>
            </Form>
            <Button @click="submit">提交</Button>
        </div>
    </template>
    
    <script>
        export default {
            name: 'HelloWorld',
            data() {
                return {
                    formValidate1: {
                        name: ''
                    },
                    formValidate2: {
                        name: ''
                    },
                    formValidate3: {
                        name: ''
                    },
                    ruleValidate: {
                        name: [
                            { required: true, message: 'The name cannot be empty', trigger: 'blur' }
                        ]
                    },
                    arr: []
                }
            },
            methods: {
                check(name){  // 验证表单是否通过
                    this.$refs[name].validate((valid) => {
                        if(valid) {
                            this.arr.push(true);  // arr 这个数组是用来存放单个表单的验证状态
                        } else {
                            this.arr.push(false);
                        }
                    })
                },
                submit(){  // 提交
                    this.arr = [];  // 重置数组
                    // 同时验证多个表单
                    this.check('formValidate1');
                    this.check('formValidate2');
                    this.check('formValidate3');
                    var flag = null;
                    for(var i = 0; i < this.arr.length; i++) {
                        if(this.arr[i]) { // 单个表单验证通过,继续验证下个表单
                            flag = true;
                            continue;
                        } else { // 单个表单验证不通过,结束
                            flag = false;
                            break;
                        }
                    }
                    if(flag){  // 验证表单成功
                        alert("验证成功");
                    }else{
                        alert("验证失败")
                    }
                }
            }
        }
    </script>
    
    <style scoped></style>

    3、Select 内的 Option 动态改变时,有时选中值未更新的问题

           需求背景:Select的下拉数组是由后台返回的,选中的值也是后台返回的。正确赋值之后,select选中的值未更新。

           解决办法:刚开始一直在不停的调试,有时候可能正确显示,有时候又不行。这个随机事件真的。。。。最后查阅官方文档,好吧,这是官方的坑,更新到iview最新版本后,问题得以解决。

                             这也给我以后很好的警示,有时候一些异常情况,可以先看哈官方的更新日志,因为我们刚开始做项目的时候,版本只是当时的最新版,一些问题可能官方后面已经修复了,所以应及时更新版本。

                            

     4、Table相关问题

           (1)render函数的运用

                              

                     参数解读:

                      h:  vue  Render函数的别名(全名 createElement)即 Render函数

                      params: table 该行内容的对象

                      props:设置创建的标签对象的属性

                      style:设置创建的标签对象的样式

                      on:为创建的标签绑定事件

                      scopedSlots:显示作用域插槽

                       a、Switch 开关

                        {
                            title: "可控开关",
                            key: "isOpen",
                            align: "center",
                             100,
                            render:(h, params) => {
                                return h('i-switch', {
                                    props: {
                                        value: params.row.isOpen ? params.row.isOpen : false,  // 指定当前是否选中  Boolean类型  (isOpen后端返回字段,根据自己接口返回数据,自行修改)
                                    },
                                    scopedSlots:{
                                        open: () => h('span', 'on'),  // 自定义显示打开时的内容
                                        close: () => h('span', 'off')  // 自定义显示关闭时的内容
                                    },
                                    on: {
                                        /*
                                         * 触发事件是on-change
                                         * 参数value是回调值  Boolean类型                                    
                                        */ 
                                        'on-change': (value) => { 
                                            this.data[params.index].isOpen = value;  // 赋值  data:表格数据
                                        }
                                    }
                                })
                            }
                        }

           

                  b、Button按钮

                        {
                            title: '操作',
                            key: 'action',
                             150,
                            align: 'center',
                            render: (h, params) => {  // 按钮操作
                                return h('div', [
                                    h('Button', {
                                        props: {
                                            type: 'primary',
                                            size: 'small'
                                        },
                                        style: {  // 自定义样式
                                            marginRight: '5px'
                                        },
                                        on: {  // 自定义事件
                                            click: () => {
                                                this.show(params.index)  // params.index是拿到table的行序列,可以取到对应的表格值
                                            }
                                        }
                                    }, '查看'),
                                    h('Button', {
                                        props: {
                                            type: 'error',
                                            size: 'small'
                                        },
                                        on: {
                                            click: () => {
                                                this.remove(params.index)
                                            }
                                        }
                                    }, '删除')
                                ]);
                            }
                        }

                     c、Input 输入框

                        {
                            title: "input输入框",
                            key: "inputText",
                            align: "center",
                            render:(h, params) => {
                                return h('Input', {
                                    props: {
                                        value: params.row.inputText ? params.row.inputText : '',
                                        size: 'small'
                                    },
                                    on: {
                                        'on-blur': (event) => {  // 输入框失去焦点时触发
                                            this.data[params.index].inputText = event.target.value;  // 赋值   data:表格数据
                                        }
                                    }
                                });
                            }
                        }

                  

                           d、Select 下拉框

                        {
                            title: 'select下拉框',
                            key: 'selectText',
                            align: 'center',
                            render: (h, params) => {
                                return h('Select',{
                                        props:{
                                            value: params.row.selectText ? params.row.selectText : '',
                                            size: 'small'
                                        },
                                        on: {
                                            'on-change':(value) => {  //  下拉框选定的值
                                                this.data[params.index].selectText = value;
                                            }
                                        }
                                    },
                                    /**
                                     * this.selectAction   下拉框Option数组
                                     * selectAction:[
                                            {
                                                value: '01',
                                                name:'select_1'
                                            },
                                            {
                                                value: '02',
                                                name:'select_2'
                                            }
                                        ]
                                     */
                                    this.selectAction.map((item) =>{  // 下拉选项
                                        return h('Option', {
                                            props: {
                                                value: item.value,
                                                label: item.name
                                            }
                                        })
                                    })
                                )
                            }
                        }

                

                        e、Rate评分

                        {
                            title: "评分",
                            key: "rate",
                            align: "center",
                            render:(h, params) => {
                                return h('Rate', {
                                    props: {
                                        value: Number(params.row.rate),  // 当前 star 数   Number类型
                                        'allow-half': true,  // 可以选中半星
                                        disabled: false  // 是否只读
                                    },
                                    on: {
                                        'on-change': (value) => {   // 评分改变时触发
                                            this.data[params.index].rate = value;  // 赋值  data:表格数据
                                        }
                                    }
                                })
                            }
                        }

                       f、Img图片

                      {
                            title: "头像",
                            key: "avatar",
                            align: "center",
                             100,
                            render:(h, params) => {
                                return h('Avatar', {  // 也可用原生img标签代替
                                    style: {  
                                         '30px',
                                        height: '30px',
                                        'border-radius': '50%'
                                    },
                                    attrs: {
                                        src: 'https://i.loli.net/2017/08/21/599a521472424.jpg'
                                    }
                                })
                            }
                        }

                      g、DatePicker时间选择器

                        {
                            title: "时间选择器",
                            key: "date",
                            align: "center",
                            render:(h, params) => {
                                return h('DatePicker', {
                                    props: {
                                        value: params.row.date,
                                        size: 'small',
                                        type: 'datetime'
                                    },
                                    on: {
                                        'on-change': (value) => {  // 输入框失去焦点时触发
                                            this.data[params.index].date = value;  // 赋值   data:表格数据
                                        }
                                    }
                                });
                            }
                        }

                         h、对数据进行处理

                                比如,后端返回时间是时间戳格式,展示给用户看的肯定不能是时间戳,这时候就需要我们对数据进行处理              

                       {
                            title: "申请年份",
                            align: "center",
                            key: "applyDate",
                            render: (h, params) => {
                                return h('span', {
                                        
                                }, new Date(params.row.applyDate).getFullYear())  // 对后端返回的时间戳进行处理,返回页面需要展示的格式
                            }
                        }

                            差不多就总结了这几个,写多了就发现,是一样的模板,直接套到render函数里面就是了。想要更多的学习render函数相关的,可以自己前往官网学习。

                            完整代码:

    <template>
        <div class="hello">
            <Table border :columns="columns" :data="data"></Table>
        </div>
    </template>
    
    <script>
        export default {
            name: 'HelloWorld',
            data() {
                return {
                    columns: [  // 表格列的配置描述
                        {
                            title: "头像",
                            key: "avatar",
                            align: "center",
                             100,
                            render:(h, params) => {
                                return h('Avatar', {  // 也可用原生img标签代替
                                    style: {  
                                         '30px',
                                        height: '30px',
                                        'border-radius': '50%'
                                    },
                                    attrs: {
                                        src: 'https://i.loli.net/2017/08/21/599a521472424.jpg'
                                    }
                                })
                            }
                        },
                        {
                            title: "时间选择器",
                            key: "date",
                            align: "center",
                            render:(h, params) => {
                                return h('DatePicker', {
                                    props: {
                                        value: params.row.date,
                                        size: 'small',
                                        type: 'datetime'
                                    },
                                    on: {
                                        'on-change': (value) => {  // 输入框失去焦点时触发
                                            this.data[params.index].date = value;  // 赋值   data:表格数据
                                        }
                                    }
                                });
                            }
                        },
                        {
                            title: "input输入框",
                            key: "inputText",
                            align: "center",
                            render:(h, params) => {
                                return h('Input', {
                                    props: {
                                        value: params.row.inputText ? params.row.inputText : '',
                                        size: 'small'
                                    },
                                    on: {
                                        'on-blur': (event) => {  // 输入框失去焦点时触发
                                            this.data[params.index].inputText = event.target.value;  // 赋值   data:表格数据
                                        }
                                    }
                                });
                            }
                        },
                        {
                            title: 'select下拉框',
                            key: 'selectText',
                            align: 'center',
                            render: (h, params) => {
                                return h('Select',{
                                        props:{
                                            value: params.row.selectText ? params.row.selectText : '',
                                            size: 'small'
                                        },
                                        on: {
                                            'on-change':(value) => {  //  下拉框选定的值
                                                this.data[params.index].selectText = value;
                                            }
                                        }
                                    },
                                    /**
                                     * this.selectAction   下拉框Option数组
                                     * selectAction:[
                                            {
                                                value: '01',
                                                name:'select_1'
                                            },
                                            {
                                                value: '02',
                                                name:'select_2'
                                            }
                                        ]
                                     */
                                    this.selectAction.map((item) =>{  // 下拉选项
                                        return h('Option', {
                                            props: {
                                                value: item.value,
                                                label: item.name
                                            }
                                        })
                                    })
                                )
                            }
                        },
                        {
                            title: "申请年份",
                            align: "center",
                            key: "applyDate",
                            render: (h, params) => {
                                return h('span', {
                                        
                                }, new Date(params.row.applyDate).getFullYear())  // 对后端返回的时间戳进行处理,返回页面需要展示的格式
                            }
                        },
                        {
                            title: "可控开关",
                            key: "isOpen",
                            align: "center",
                             100,
                            render:(h, params) => {
                                return h('i-switch', {
                                    props: {
                                        value: params.row.isOpen ? params.row.isOpen : false,  // 指定当前是否选中  Boolean类型  (isOpen后端返回字段,根据自己接口返回数据,自行修改)
                                    },
                                    scopedSlots:{
                                        open: () => h('span', 'on'),  // 自定义显示打开时的内容
                                        close: () => h('span', 'off')  // 自定义显示关闭时的内容
                                    },
                                    on: {
                                        /*
                                         * 触发事件是on-change
                                         * 参数value是回调值  Boolean类型                                    
                                        */ 
                                        'on-change': (value) => { 
                                            this.data[params.index].isOpen = value;  // 赋值  data:表格数据
                                        }
                                    }
                                })
                            }
                        },
                        {
                            title: "评分",
                            key: "rate",
                            align: "center",
                            render:(h, params) => {
                                return h('Rate', {
                                    props: {
                                        value: Number(params.row.rate),  // 当前 star 数   Number类型
                                        'allow-half': true,  // 可以选中半星
                                        disabled: false  // 是否只读
                                    },
                                    on: {
                                        'on-change': (value) => {   // 评分改变时触发
                                            this.data[params.index].rate = value;  // 赋值  data:表格数据
                                        }
                                    }
                                })
                            }
                        },
                        {
                            title: '操作',
                            key: 'action',
                             150,
                            align: 'center',
                            render: (h, params) => {  // 按钮操作
                                return h('div', [
                                    h('Button', {
                                        props: {
                                            type: 'primary',
                                            size: 'small'
                                        },
                                        style: {  // 自定义样式
                                            marginRight: '5px'
                                        },
                                        on: {  // 自定义事件
                                            click: () => {
                                                this.show(params.index)  // params.index是拿到table的行序列,可以取到对应的表格值
                                            }
                                        }
                                    }, '查看'),
                                    h('Button', {
                                        props: {
                                            type: 'error',
                                            size: 'small'
                                        },
                                        on: {
                                            click: () => {
                                                this.remove(params.index)
                                            }
                                        }
                                    }, '删除')
                                ]);
                            }
                        }
                    ],
                    data: [  // 表格数据
                        {
                            inputText: '18',
                            isOpen: false,
                            selectText : '02',
                            rate: 4,
                            date: '2019-02-03 00:08:45',
                            applyDate: 1551835636920
                        },
                        {
                            inputText: '',
                            isOpen: true,
                            selectText : '01',
                            rate: 1.5,
                            date: '',
                            applyDate: 1506124800000
                        }
                    ],
                    selectAction:[
                        {
                            value: '01',
                            name:'select_1'
                        },
                        {
                            value: '02',
                            name:'select_2'
                        }
                    ]
                    
                }
            },
            methods: {
                show (index) {  // 查看
                    this.$Modal.info({
                        title: '查看',
                        content: '查看详情'
                    })
                },
                remove (index) {  // 删除
                    this.data.splice(index, 1);
                }
            }
        }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
        .hello{
             90%;
            margin: 0 auto;
            padding: 20px 50px 0;
        }
    </style>
    View Code

                            

              (2)selection的多选来做单选:

                         通过给 columns 数据设置一项,指定 type: 'selection',即可自动开启多选功能,但是有些产品觉得iview的单选效果不好,非要用selection的来做单选。以下是解决方案:

                         {
                            title: '选择',
                            align:'center',
                            key: 'checkBox',
                             80,
                            render:(h,params)=>{
                                return h('div',[
                                    h('Checkbox',{
                                        props:{
                                            value: params.row.checkBox
                                        },
                                        on:{
                                            'on-change':(e)=>{
                                                this.data.forEach((item)=>{ // 先取消所有对象的勾选,checkBox设置为false
                                                    this.$set(item, 'checkBox', false);
                                                });
                                                this.data[params.index].checkBox = e;  // 再将勾选的对象的checkBox设置为true
                                            }
                                        }
                                    })
                                ])
                            }
                        }

         

                 (3)结合Page分页组件一起使用

                       一般来讲,在表格数据比较多的情况下,会对表格进行分页展示

    <Table border :columns="columns" :data="data"></Table>
    <Page style="float: right;margin-top:20px" :total="page.total" :current="page.current" :page-size="page.size" @on-change="changePage"  @on-page-size-change="changePageSize" show-total show-elevator show-sizer />

                   

                     分页一般有2种:前端分页、后端分页。前端分页就是前端一次性拿到所有数据,再对拿到的数据进行分页展示。后端分页就是前端一次只拿一页的数据展示,分页的时候再次请求后端。

            mounted(){
                this.changeTableData();
            },
            methods: {
                changePage(current){  // 页码改变的回调,返回改变后的页码
                    this.page.current = current;
                    this.changeTableData();
                },
                changePageSize(size){  // 切换每页条数时的回调,返回切换后的每页条数
                    this.page.current = 1;
                    this.page.size = size;
                    this.changeTableData();
                },
                changeTableData(){
                    /**
                     * page定义
                     * page: {
                            total: 0, 总数
                            current: 1, // 当前页码
                            size: 10  // 每页个数
                        }
                     *
                     *
                     * data: 表格展示数据
                     * tableData: 后端返回的所有数据
                     *  
                     */
    
                    // 前端分页
                    let _start, _end;
                    let page = this.page;
                    _start = (page.current - 1) * page.size;
                    _end = page.current * page.size;
                    this.data = this.tableData.slice(_start, _end);
                    page.total = this.tableData.length;
    
                    // 后端分页
                    // ajax请求后端接口,重新获取数据
                }
            }

                    使用了type=index,分页之后,索引还是从1开始,如何实现累加呢?

                    使用render函数可解决:

                      {
                            title: '序号',
                            align:'center',
                            type: 'index2',
                             80,
                            render: (h, params) => {
                                return h('span', params.index + (this.page.current - 1) * this.page.size + 1);
                            }
                        }

                    在翻页之后,如何记住checkbox多选的选中和未选中状态?

                    用一个数组checkData来装选中的数据,在每次表格数据改变时,通过比对数据来进行回填选中状态。

    <Table border :columns="columns" :data="data" @on-select="changeSelect" @on-select-cancel="changeSelectCancel" @on-select-all="changeSelectAll" @on-select-all-cancel="changeSelectAllCancel"></Table>
             methods: {
                changeSelect(data, val){  // 选中某个数据
                    /**
                     * checkData  多选框选中的数组
                     * id  每条数据的唯一标识
                     */
                    for(let i in this.checkData){
                        if(val.id === this.checkData[i].id){
                            this.checkData.splice(i, 1);
                            break;
                        }
                    }
                    this.checkData.push(val);
                },
                changeSelectCancel(data, val){  // 取消某个数据
                    for(let i in this.checkData){
                        if(val.id === this.checkData[i].id){
                            this.checkData.splice(i, 1);
                            break;
                        }
                    }
                },
                changeSelectAll(data){  // 多选选中
                    let arr = [];
                    for(let i in data){
                        let flag = true;
                        for(let y in this.checkData){
                            if(data[i].id === this.checkData[y].id){ // 已有数据
                                flag = false;
                                break;
                            }else{
                                continue;
                            }
                        }
                        if(flag){  // 添加新数据
                            arr.push(data[i]); 
                        }
                    }  
                    this.checkData = this.checkData.concat(arr); 
                },
                changeSelectAllCancel(data){  // 多选取消
                    for(let i in this.data){ // 取消当前页的内容
                        for(let y in this.checkData){
                            if(this.data[i].id === this.checkData[y].id){
                                this.checkData.splice(y, 1);
                                break;
                            }
                        }
                    }
                },
            },
            watch:{
                'data':{
                    handler:function(newValue, oldValue){
                        this.data = newValue;
                        for(let i in this.data){
                            let flag = false;
                            for(let y in this.checkData){
                                if(this.data[i].id === this.checkData[y].id){
                                    flag = true;
                                    break;
                                }else{
                                    continue;
                                }
                            }
                            if(flag){  // 回填选中状态
                                this.data[i]._checked = true;
                            }else{
                                this.data[i]._checked = false;
                            }
                        }
                    },
                    deep:true
                }
            }

    5、定制iview主题

         按照官网,一步一步做的,最后却报错:

        

       那是因为less的版本过高,重新卸载,安装3.0以下的版本(比如2.7.3版本),即可解决问题。

    六、合并表格单元行

       官网已经提供了表头分组的api。可是我们想合并单元行列怎么办呢,虽然官网没提供api,但是好在我们可以用render函数自定义渲染行列。

       1、合并行

                       {
                            title: '合并行',
                            align:'center',
                            key: 'content',
                            render: (h, params) => {
                                let a = ['数学','语文']; 
                                return this.renderData(h, a);
                           }
                        }
    
    
    
                // 下面为渲染方法
                renderData(h, a){
                    let b = [];
                    a.map((val, index) => {
                        b.push(h("p", {
                            style: {
                                height: "40px",
                                lineHeight: "40px",
                                "width": "100%",
                                "display": "block",
                                "padding": "0 10px",
                                borderBottom: a.length !== index + 1 ? "1px solid #e8eaec" : "none"
                            }}, val)
                        )
                    })
                    return b;
                }

    2、合并列

                      {
                            title: '姓名,昵称',
                            align:'center',
                            key: 'name',
                            renderHeader: (h, params) => {  // 自定义表头
                                let a = ['姓名', '昵称'];
                                return this.renderColumnData(h, a);
                            },
                            render: (h, params) => {
                                let a = ['张三', '李四'];
                                if(params.row.same){  // 名字姓名相同
                                    a = ['王二麻子'];
                                }
                                return this.renderColumnData(h, a);
                           }
                        },
    
                 // 下面为渲染的方法
                 renderColumnData(h, a){  // 渲染合并列
                    let b = [];
                    let percent = a.length === 0 ? 100 : (Math.floor(100 / a.length * 100) / 100);
                    a.map((val, index) => {
                        b.push(h("p", {
                            class: a.length !== index + 1 ? "has-border" : "",
                            style: {
                                 `${percent}%`,
                                padding:'4px 8px',
                                'display': 'flex',
                                'align-items': 'center',
                                'justify-content': 'center'
                            }}, val)
                        )
                    })
                    let header = h('div',{
                        class: 'custom-header'
                    }, b);
                    return header;
                }

    还需添加css样式

       .ivu-table-cell{
            padding: 0 !important;
             100%;
        }
        .ivu-table-cell .has-border{
            position: relative;
        }
        .ivu-table-cell .has-border::after{
            content: '';
            position: absolute;
             1px;
            background-color: #e8eaec;
            top: 0;
            bottom: 0;
            right: 0;
        }
        .custom-header{
             100%;
            height: 100%;
            display: flex;
        }

    需要注意的是  iview 里面的 ivu-table-cell  class样式  没添加height:100%。但是由于自定义列的时候,右边框的高度要100%,所以只能根据子元素手动改父节点 ivu-table-cell,添加样式。

    在初始化,和改变表格数据的时候都需执行一次

               changeCustomHeight(){
                    let customArr = document.getElementsByClassName('custom-header');  //custom-header   render函数里面自定义的class
                    for(let i in customArr){
                        if(customArr[i].parentNode){
                            customArr[i].parentNode.style.height = "100%";
                        }
                    }
                },

    页面效果预览:

    说明:此方法主要还是通过改变样式来实现效果,对于一些特殊的比较复杂的合并行列,可能无法实现。

     

  • 相关阅读:
    mySQL远程访问
    PHP安装amqp操作记录
    storm与daemontools安装详解
    centos时间同步问题
    nf_conntrack: table full, dropping packet 解决
    rabbitmq主从搭建
    jsonp
    django 整理二
    django中表单验证
    ajax
  • 原文地址:https://www.cnblogs.com/yanxulan/p/10407029.html
Copyright © 2011-2022 走看看