Vue & Antd 經驗總結

antd form 代碼模板

form 表單取值賦值 

this.form.getFieldDecorator('createTimeArr', { initialValue: [moment(createDateObj.startDate, 'YYYY-MM-DD hh:mm:ss'), moment(createDateObj.endDate, 'YYYY-MM-DD hh:mm:ss')] })
this.form.getFieldDecorator('payPeriods', { initialValue: record.payPeriods })
this.form.setFieldsValue({ taxType: this.contractInfo.taxType })
this.form.getFieldValue('password')
this.form.getFieldDecorator('planPayTime', { initialValue: moment(record.planPayTime, 'YYYY-MM-DD hh:mm:ss') })
this.form.setFieldsValue({ 'createTimeArr': [moment(createDateObj.startDate, 'YYYY-MM-DD'), moment(createDateObj.endDate, 'YYYY-MM-DD')] })
this.form.setFieldsValue({ planPayTime: moment(record.planPayTime, 'YYYY-MM-DD') })
this.cachePayData.planPayTime.format('YYYY-MM-DD')

下拉框初始化賦值

<a-select placeholder="請選擇開票類型" v-decorator="[ 'taxType', {rules: [{ required: true, message: '請選擇開票類型'}]} ]">
  <a-select-option :value="0">增值稅普票</a-select-option>
  <a-select-option :value="1">增值稅專票</a-select-option>
</a-select>

<script>
    create: {
        this.form.getFieldDecorator('taxType', { initialValue: this.contractInfo.taxType })
    }
</script>
<a-select placeholder="請選擇支付單位" v-decorator="['paymentCardId',{rules: [{required: true, message: '請選擇支付單位!'}]}]">
    <a-select-option value="-1">全部</a-select-option>
    <a-select-option v-for="emPayment in emPayments" :key="emPayment.id" :value="emPayment.id">{{ emPayment.cardName }}</a-select-option>
</a-select>

<script>
    data () {
        return {
            emPayments: []
        }
    },
    create: {
        queryPaymentCard({ cardState: 0 })
        .then(res => {
          this.emPayments = []
          this.emPayments = res.data
        })
    }
</script>
<a-select v-model="queryParam.createEmpId" :dropdownStyle="{ position: 'fixed' }" :options="employees" placeholder="全部">
</a-select>

<script>
    data () {
        return {
            employees: [{ value: '-1', label: '全部' }],
        }
    },
    create: {
        sysEmployee.querySysEmployee({ delState: 0 })
        .then(res => {
          this.employees = res.data
          this.employees.unshift({ value: '-1', label: '全部' })
        })
    }
</script>
<!-- 下面是sql語句 -->
select
    id value, emp_name label
from
    sys_employee

 單選框

<a-radio-group :value="taxNature" style="margin-left:24px;" name="taxNature" @change="handleTaxNature">
    <a-radio-button :value="1">企業</a-radio-button>
    <a-radio-button :value="0">個人</a-radio-button>
</a-radio-group>
<script>
    data () {
        return {
            taxNature: 1
        }
    },
    method: {
        handleTaxNature (e) {
          this.taxNature = e.target.value
        }
    }
</script>

 

ref屬性與refs

在Vue中一般很少會用到直接操作DOM,但不可避免有時候需要用到,這時我們可以通過ref和$refs這兩個來實現。 

ref 被用來給DOM元素或子組件註冊引用信息。引用信息會根據父組件的 $refs 對象進行註冊。如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子組件上,引用信息就是組件實例。

關於ref 註冊時間的重要說明:因爲 ref 本身是作爲渲染結果被創建的,在初始渲染的時候你不能訪問它們,它們還不存在!$refs也不是響應式的,因此你不應該試圖用它在模板中做數據綁定。

注意:只要想要在Vue中直接操作DOM元素,就必須用ref屬性進行註冊。

普通DOM

通過原生 JavaScript 方式來獲取:

<span id="demo">演示JS操作DOM節點</span>
console.log(document.getElementById("demo").innerHTML);

通過 ref 屬性來獲取:

<span id="demo" ref="mydemo">演示ref操作DOM節點</span>
console.log(this.$refs.mydemo.innerHTML);

添加組件

在子組件中使用 ref 屬性,會將子組件添加到父組件的$refs對象中。

<create-form ref="createModal" />

$refs 中綁定有我們的 createModal 組件,而且還看到了對應的組件中的 msg屬性和 show方法,那這樣我們可以調用了

this.$refs.createModal.show();
console.log(this.$refs.createModal.msg);

 

vue中父組件調用子組件的方法並傳遞參數

1. 利用 $refs 將數據作爲參數傳遞給子組件並調用子組件的方法。

父組件:

<a @click="handleEdit(record)">編輯</a>

<!-- 編輯組件 -->
<edit-form ref="editModal" />
handleEdit (record) {
    // 調用ref爲editModal的組件中的add方法
    this.$refs.editModal.add(record)
}

 子組件:

add (editObj) {
    this.editData = editObj
},

2. 子組件中 watch(監聽)父組件數據的變化。 

注意:如果 watch 監聽的數據不是基本類型,而是對象、數組,需要進行深度監聽

監聽數組

data() {  
    return {  
        showData: new Array(11).fill(0)
    }
},  
watch: {
  showData: { // 監視showData屬性的變化
    handler(newValue, oldValue) {
           // 變化後的回調函數  
      this.newData = newValue 
    },
    deep: true  // deep爲true,會監視showData的屬性及屬性中的對象屬性變化
  }
} 

監聽對象 

data() {
  return {
    bet: {
      pokerState: 53,
      pokerHistory: 'local'
    }   
    }
},
watch: {
  bet: {
    handler(newValue, oldValue) {
      console.log(newValue)
    },
    deep: true
  }
}

只要 bet 中的屬性發生變化(可被監測到的),便會執行handler函數;
但是 watch 只能監控整個對象,如果只想監測該對象某一個具體的屬性的變化,如 pokerHistory 變化時,才執行handler函數,則可以利用計算屬性 computed 做中間層。

data() {
  return {
    bet: {
      pokerState: 53,
      pokerHistory: 'local'
    }   
    }
},
computed: {
  pokerHistory() {
    return this.bet.pokerHistory
  }
},
watch: {
  pokerHistory(newValue, oldValue) {
    console.log(newValue)
  }
}

注意:

  • 父組件改變props,子組件如果直接使用props,會觸發子組件更新。
  • 父組件改變props,子組件如果將props放進data中再使用,不會觸發子組件更新。
  • 父組件改變props,子組件如果將props放進computed中再使用,會觸發子組件更新。
  • data,props和computed的變化都會觸發組件更新

 

子組件中調用父組件中的方法,並傳遞參數

父組件: 

<!-- 在父組件中引入的子組件 -->
<create-form ref="createModal" @choose="handleChooseOk" />
// 父組件中的方法
handleChooseOk (record) {
  this.contractInfo.title = record.title
  this.contractInfo.taxNature = record.taxNature
  this.contractInfo.taxType = record.taxType
  this.contractInfo.taxCode = record.taxCode
  this.contractInfo.phone = record.phone
  this.initIm()
}

子組件:

choose (record) {
    this.visible = false
    //調用父組件中的方法並傳遞record參數
    this.$emit('choose', record)
}

 

頁面間方法調用

方法一:以員工信息管理爲例,在員工信息編輯頁(empEdit)中調用員工信息管理頁面(empMain)的方法。

1. 在empMain 的data屬性中增加字段 id, id的值應是唯一的(建議與頁面的名稱一致)

export default {
  name: 'sysEmployeeMain'
data () {
    return {
      id: 'sysEmployeeMain'
},  

2. 在empMain 的methods中定義提供給 empEdit 調用的方法 test()

method: {
    test (param){
        alert(param)
    }
}

3. 在empEdit的created方法中獲取empMain對象:

data () {
    return {
        mainForm: {}
    }
},
created () {
    this.mainForm = this.$parent.$children.find(item => item.id === 'empMain')
},

4. 調用empMain中的test()方法

methods: {
    initDefaultValue () {
        this.mainForm.test(111)
    }
}

方法二:

this.$router.push({ name: 'pmProjectContractApproval', 
                    params: { opt: 'pmProjectContractApproval', mainForm: this } })

pmProjectContractApproval.vue

data () {
    return {
        mainForm: {}
    }
}
methods: {
    init () {
        this.mainForm = this.$route.params.mainForm
    },
    submit () {
        this.mainForm.refreshTable(false)
    }
}

 

vue-router 攜帶參數跳轉頁面

query方式傳參和接收參數 

// 傳參: 
this.$router.push({
        path:'/xxx',
        query:{
          id:id
        }
      })
  
// 接收參數:
this.$route.query.id

params方式傳參和接收參數

// 傳參: 
this.$router.push({
        name:'xxx',
        params:{
          id:id
        }
      })
  
// 接收參數:
this.$route.params.id
  • 1.$router爲VueRouter實例,想要導航到不同URL,則使用$router.push方法
  • 2.$route爲當前router跳轉對象,裏面可以獲取name、path、query、params等

 

nextTick()

vue是依靠數據驅動視圖更新的,該更新的過程是異步的。即:當偵聽到你的數據發生變化時, Vue將開啓一個隊列(該隊列被Vue官方稱爲異步更新隊列)。視圖需要等隊列中所有數據變化完成之後,再統一進行更新。

nextTick()的用法有兩種:

Vue.nextTick([callback, context])
vm.$nextTick([callback])

兩個方法的作用都是在DOM更新循環結束之後執行延遲迴調。當我們改變了數據的時候,DOM的渲染需要時間,然而我們希望去操作DOM元素,就需要等待渲染完成後再去操作。就需要用到 nextTick,將等待DOM渲染完成後需要的操作放在回調函數裏。

 

ant design vue中表格指定格式渲染

注意點:定義的columns一定要寫在data中,否則在加載過程中由於渲染順序會導致其中的渲染函數無法識別

指定渲染函數:

{
    title: '審覈狀態',
    dataIndex: 'isReview',
    customRender: (text, row, index) => {
        if (row.isReview === 0) {
            return '未審覈'
        } else {
            return '已審覈'
        }
    }
},
{
    title: '搜索關鍵詞',
    dataIndex: 'keyword',
    customRender: (text, row, index) => {
        if (index < 4) { // 前4行數據以a標籤的形式被渲染
            return <a href="javascript:;">{text}</a>
        }
        return { // 否則以獨佔4列的文本形式被渲染
            children: text,
                attrs: {
                    colSpan: 4
                }
            }
        }
}

調用插槽模板:

<a-table :columns="columns" :dataSource="data" :pagination='pagination'>
    <template slot="operation">
        <a-select placeholder="選擇操作" style="width: 100%" @change="listHandleChange">
            <a-select-option value="1">項目進度</a-select-option>
            <a-select-option value="2">質量管控</a-select-option>
            <a-select-option value="3">運維監控</a-select-option>
        </a-select>
    </template>
    <template slot='progress' slot-scope="text,record">
        <span>{{text}}</span>
        <span v-if='record.progressstatus'><a-icon type="arrow-up" /></span>
        <span v-if='!record.progressstatus'><a-icon type="arrow-down" /></span>
    </template>
</a-table>
{
    title: '項目進度',
    dataIndex: 'progress',
    // 模板中對應的slot-scope可以用來傳遞參數,其中第一個參數是當前字段progress對應的值,
    // 第二個參數是當前字段對應的所有值對象,即整個data[n]
    scopedSlots: { customRender: 'progress' } 
}, 
{
    title: '操作',
    dataIndex: 'operate',
    scopedSlots: { customRender: 'operation' } // 直接對應插槽名爲operation的模板
}

 

antd 多行表單操作(遇到的一個大難題)

曾經接到這樣的需求:

1期款和2期款都分別有各自的本次回款和本次優惠,並且上面的本次回款金額和本次優惠金額會統計兩期本次回款和本次優惠的和。

點擊結清按鈕,如果選是,則自動將本次回款填滿並禁用該 input 組件

上圖中的本次回款我使用了插槽slot來處理。

<span slot="nowBackMoney" slot-scope="text, record, index">
    <!-- 一定要設置不同的key,要不然多行表單的v-decorator相同,會造成數據互相干擾 -->
    <a-form :key="index" :form="form">
        <a-form-item style="margin-bottom: -2px">
            <a-input
                placeholder="請輸入本次回款"
                @change="e => handleInputChange(e.target.value, record)"
                v-decorator="[
                'nowBackMoney'
                ]" />
        </a-form-item>
    </a-form>
</span>

問題:碰到第一個難題就是輸入本次回款時,上下兩行數據互相干擾,輸入上一行數據,下一行也自動輸入了這個數據 :

解決辦法:使用 key 唯一令牌解決表單值混亂

我要將各自的本次回款存到各自的對象中,這個通過監聽方法監聽輸入的內容,並傳入代表當前行數據的 record 參數就可以做到了。

// 保存輸入的本次回款並計算總回款
handleInputChange (value, record) {
    record.nowBackMoney = value 
    //record就是當前行的數據。這樣當前行某單元格輸入的數據不用太多複雜的操作就存到了各自行中的nowBackMoney屬性中
    var nowBackMoneySum = 0
    this.data.forEach(item => {
        nowBackMoneySum += parseFloat(item.nowBackMoney)
    })
    this.form.setFieldsValue({ nowBackMoneySum: nowBackMoneySum })
}

問題:點擊結清按鈕的時候,我發現又出現了數據同步的問題。我點上面的是,下面的也選是。代碼如下:

解決辦法:isBackAll 變量是我聲明在data中的變量。兩個按鈕都用的它一個。正是因爲這個產生的互相干擾。於是我又想像上面的解決方式那樣利用 record 來解決這個問題。具體就是在後臺對應類中定義一個變量 isBackAll,單選框的value值用record.isBackAll 的方式來賦值,這樣就不會互相干擾了。

這樣,利用下面的辦法,就可以各自統計各自的數據了:

 

表格設置選中行自動選中複選框

<s-table
    ref="table"
    size="default"
    rowKey="id"
    :columns="columns"
    :data="loadData"
    :alert="options.alert"
    :rowSelection="options.rowSelection"
    :customRow="rowClick" // 點擊每一行的事件
    showPagination="auto"
>

在 data 中定義好下面這些屬性及方法

    selectedRowKeys: [],
    selectedRows: [],
    options: {
        alert: { show: true, clear: () => { this.selectedRowKeys = [] } },
        rowSelection: {
          selectedRowKeys: this.selectedRowKeys,
          onChange: this.onSelectChange
        }
    },
    optionAlertShow: false,
    // 行點擊事件
    rowClick: (record, index) => ({
        on: {
            // 注:不僅可以添加點擊事件還可以添加其他的事件
            click: () => {
                let flag = false
                if (this.selectedRowKeys.findIndex(item => item === record.id) >= 0) {
                    flag = true
                }
                if (flag) {
                    this.selectedRowKeys.splice(this.selectedRowKeys.findIndex(item => item === record.id), 1)
                    this.selectedRows.splice(this.selectedRows.findIndex(item => item.id === record.id), 1)
                } else {
                    this.selectedRowKeys.push(record.id)
                    this.selectedRows.push(record)
                }
            }
        }
    })

這麼寫有個問題:選中行時只更新數組, 但不會顯示選中複選框, 需要手動點擊一次複選框之後點行選框才起作用, 所以要繼續改進。

methods: {
    onSelectChange (selectedRowKeys, selectedRows) {
        this.selectedRowKeys = selectedRowKeys
        this.selectedRows = selectedRows
        // 在監聽選擇事件里加入下面這段代碼即可解決這個問題
        this.options = {
            rowSelection: {
                selectedRowKeys: selectedRowKeys,
                onChange: this.onSelectChange
            }
        }
    }
}

 

數組根據YYYY-MM-DD格式時間字符串排序

changeDate () {
    this.resList.sort((a, b) => {
        let aTimeString = a.planPayTime
        let bTimeString = b.planPayTime
        aTimeString = aTimeString.replace(/-/g, '/')
        bTimeString = bTimeString.replace(/-/g, '/')
        let aTime = new Date(aTimeString).getTime()
        let bTime = new Date(bTimeString).getTime()
        return aTime - bTime // 升序排列,把它倆順序換一下就是降序了
    })
}

 

禁止彈出層的底層的頁面隨着鼠標滑動

show () { // 顯示彈出層
    this.visible = true
    this.stopMove()
},
cancel () { // 關閉彈出層
    this.visible = false
    this.move()
},
stopMove () { // 禁止滾動
    const m = function (e) { e.preventDefault() }
    document.body.style.overflow = 'hidden'
    document.addEventListener('touchmove', m, { passive: false }) // 禁止頁面滑動
},
move () { // 恢復滾動
    var m = function (e) { e.preventDefault() }
    document.body.style.overflow = '' // 出現滾動條
    document.removeEventListener('touchmove', m, false)
},

 

下拉框增加搜索功能

<a-select
    v-model="queryParam.createEmpId"
    placeholder="請選擇創建人"
    showSearch
    optionFilterProp="children"
    :filterOption="this.filterOption"
>

// 單選下拉,搜索回調
filterOption (input, option) {
    return (
        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
    )
}

 

DatePicker 設置結束日期不可小於開始日期

<a-date-picker
    :disabledDate="disabledStartDate"
    v-model="queryParam.createTimeS"
    placeholder="請輸入開始時間"
/>
<a-date-picker
    :disabledDate="disabledEndDate"
    placeholder="請輸入結束時間"
    v-model="queryParam.createTimeE"
/>
disabledStartDate (createTimeS) {
    const createTimeE = this.queryParam.createTimeE
    if (!createTimeS || !createTimeE) {
        return false
    }
    return createTimeS.valueOf() > createTimeE.valueOf()
},
disabledEndDate (createTimeE) {
    const createTimeS = this.queryParam.createTimeS
    if (!createTimeE || !createTimeS) {
        return false
    }
    return createTimeS.valueOf() >= createTimeE.valueOf()
},

 

validator 方法實現表單驗證

比如說驗證兩次密碼輸入是否一樣

<a-form-item :label="msgTool.labelSpace('舊密碼')">
    <a-input 
        v-decorator="[ 'oldPwd', 
        {rules: [{ required: true, message: '請輸入密碼'}]} ]"
    />
</a-form-item>
<a-form-item :label="msgTool.labelSpace('確認密碼')">
    <a-input 
        v-decorator="['newPwd',
        {rules: [{validator: (rules, value, callback) =>{handleCheckPwd(rules, value, callback)}}]}]"
    />
</a-form-item>
handleCheckPwd (rules, value, callback) {
    var newPwd = this.form.getFieldValue('newPwd')
    var oldPwd = this.form.getFieldValue('oldPwd')
    if (newPwd != oldPwd) {
        callback(new Error('兩次的密碼不一樣'))
    } else {
        callback()
}
    

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章