記一次開發過程中,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",
                        width: 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',
                        width: 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",
                        width: 100,
                        render:(h, params) => {
                            return h('Avatar', {  // 也可用原生img標簽代替
                                style: {  
                                    width: '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",
                        width: 100,
                        render:(h, params) => {
                            return h('Avatar', {  // 也可用原生img標簽代替
                                style: {  
                                    width: '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",
                        width: 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',
                        width: 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{
        width: 90%;
        margin: 0 auto;
        padding: 20px 50px 0;
    }
</style>
View Code

                        

          (2)selection的多選來做單選:

                     通過給 columns 數據設置一項,指定 type: 'selection',即可自動開啟多選功能,但是有些產品覺得iview的單選效果不好,非要用selection的來做單選。以下是解決方案:

 

                     {
                        title: '選擇',
                        align:'center',
                        key: 'checkBox',
                        width: 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',
                        width: 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: {
                            width: `${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;
        width: 100%;
    }
    .ivu-table-cell .has-border{
        position: relative;
    }
    .ivu-table-cell .has-border::after{
        content: '';
        position: absolute;
        width: 1px;
        background-color: #e8eaec;
        top: 0;
        bottom: 0;
        right: 0;
    }
    .custom-header{
        width: 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%";
                    }
                }
            },

 

頁面效果預覽:

說明:此方法主要還是通過改變樣式來實現效果,對於一些特殊的比較復雜的合並行列,可能無法實現。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM