Vue 开发注意点(更新中)

920 阅读3分钟

1. computed created beforeCreate 执行顺序

首先看 Vue 初始化的源码:

vue/src/core/instance/init.js:

// 首先是合并参数
// merge options
if (options && options._isComponent) {
  // optimize internal component instantiation
  // since dynamic options merging is pretty slow, and none of the
  // internal component options needs special treatment.
  initInternalComponent(vm, options)
} else {
  vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
  )
}

vm._self = vm
initLifecycle(vm)    // 初始化生命周期
initEvents(vm)       // 初始化事件中心
initRender(vm)       // 初始化渲染
callHook(vm, 'beforeCreate')  // 调用生命周期钩子函数 beforeCreate
initInjections(vm)
initState(vm)  // 初始化data、props、computed、watcher 等等
initProvide(vm)
callHook(vm, 'created')  // 调用生命周期钩子函数 created

Vue 中通常在created钩子函数里执行访问数据库的方法,然后返回数据给前端,前端data中定义全局变量接收数据。

一般可以在created函数中调用ajax获取页面初始化所需的数据。

created: 往模板渲染成html或者模板编译进路由前调用created。

mounted: 已完成模板已经渲染或el对应html渲染后。

我们从图中看两个节点:

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。

mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

1.1 参考

vue的created函数中,方法的执行顺序

Vue进阶(三十六):vue.js中created方法的使用详解

2. img :src 绑定问题

先渲染了页面,然后执行了两次接口的方法。
解决方案:
加上 v-if="QPAY_First_Bank_Code"
如果有值, 才让它显示

<img :src="('/images/bank-logo-map/' + QPAY_First_Bank_Code + '.png')"
    v-if="QPAY_First_Bank_Code" />
<!-- <img :src="('/images/bank-logo-map/' + item.bankCode + '.png')" /> -->
<!-- 对数据,进行截取 -->
<img :src="('/images/bank-logo-map/' + (item.unionpayBankCode).slice(0, (item.unionpayBankCode).length-2) + '.png')" />

Vue 利用 通道,时间格式化

// html里:
<div id="app" v-cloak>
    <p>{{ timeDate | formatDate }} </p>
</div>

// index.js
let padDate = function (val) {
    val = val < 10 ? '0' + val:val;
    return val;
}

//
var app = new Vue({
    el: '#app',
    data: {
        timeDate: new Date()
    },
    filters: {
        formatDate: function (val) {
            let value = new Date(val);
            let year = value.getFullYear();
            let month = padDate(value.getMonth()+1);
            let day = padDate(value.getDate());
            let hour = padDate(value.getHours());
            let minutes = padDate(value.getMinutes());
            let seconds = padDate(value.getSeconds());
            return year + '-' + month + '-' + day +' '+hour+':'+minutes+':'+seconds;
        }
    }
})

3. v-if / v-else

用来切换图标:

<span class="quick-payment-sign-A"
    v-if="item.cardType == 1">储蓄卡</span>
<span class="quick-payment-sign-B"
    v-else>信用卡</span>

4. 可以用 v-show="" 来控制 哪个 li 显示

可以用 v-show="payWayCodeValue == 'B2C_C'" 来控制 哪个 li 显示

用 v-show="payWayCodeValue == 'B2C_C'" 控制 哪个 a 显示

三个 li,每次只显示,一个

<pax-row>
    <pax-col :span="4">选择银行:</pax-col>
    <pax-col :span="20">
        <div class="choose-bank">
            <ul>
                <!-- 个人用户 - 储蓄卡 -->
                <li v-for="(item, index) in bankList_B2C_C_Filter"
                    @click="chooseBank($event, index, item)"
                    :key="'B2C_C' + index"
                    :class="{' choose-bank-selected': chooseBankFlag == index}"
                    v-show="payWayCodeValue=='B2C_C'" >
                    <img :src="('/images/bank-logo-map/' + item.bankCode + '.png')" />
                    <span>{{item.bankName}}</span>
                    <i></i>
                </li>
                
                <!-- 个人用户 - 信用卡/储蓄卡 -->
                <li v-for="(item, index) in bankList_B2C_D_Filter"
                    @click="chooseBank($event, index, item)"
                    :key="'B2C_D' + index"
                    :class="{'choose-bank-selected': chooseBankFlag == index}"
                    v-show="payWayCodeValue == 'B2C_D'" >
                    <span>{{item.bankName}}</span>
                    <i></i>
                </li>
                
                <!-- 企业用户 -->
                <li v-for="(item, index) in bankList_B2B_Filter"
                    @click="chooseBank($event, index, item)"
                    :key="'B2B' + index"
                    :class="{' choose-bank-selected': chooseBankFlag == index}"
                    v-show="payWayCodeValue == 'B2B'" >
                    <img :src="('/images/bank-logo-map/' + item.bankCode + '.png')" />
                    <span>{{item.bankName}}</span>
                    <i></i>
                </li>
            </ul>
        </div>
        
        <a class="expand-choose-bank"
            href="javascript:;"
            @click="chooseBankExpand"
            v-show="payWayCodeValue == 'B2C_C'" >
            查看更多银行1
            <pax-icon :type="chooseBankIcon_B2C_C" />
        </a>
        
        <a class="expand-choose-bank"
            href="javascript:;"
            @click="chooseBankExpand"
            v-show="payWayCodeValue == 'B2C_D'" >
            查看更多银行2
            <pax-icon :type="chooseBankIcon_B2C_D" />
        </a>
        
        <a class="expand-choose-bank"
            href="javascript:;"
            @click="chooseBankExpand"
            v-show="payWayCodeValue == 'B2B'" >
            查看更多银行3
            <pax-icon :type="chooseBankIcon_B2B" />
        </a>
    </pax-col>
</pax-row>

5. 通过 this.$emit 自组件 向父组件,传递值

子组件:

<!-- 添加银行卡 -->
<p class="item card-add-A"
    @click="bindCard()" >
    <span class="item_icon">
        <img src="/images/add-bank.png" alt="">
    </span>
    <span class="item_name">添加银行卡</span>
    <!-- 图标 -->
    <i></i>
</p>

methods:{
    // 绑卡
    bindCard(){
        // 触发父组件的v-on:bind="bindCardFunc"方法
        this.$emit('bind');
    }
}

父组件:

<!-- 自己封装的 actionsheet 全局插件 -->
<VActionsheet :open="openActionsheet" v-on:show="func"
    v-on:bind="bindCardFunc"
    :tradesBanksData="tradesBankInfoObj" >
</VActionsheet>

methods: {
    //子组件, 触发的 bindCardFunc 方法
    bindCardFunc (){
        alert(1);
        this.$router.push('/my_form/my_form')
    }
}

6. eventBus

当页面之间,没有引用关系的时候,可以用 eventBus 来传值。

7. xxx

8. 一个页面自动提交表单的例子

在 views 目录下,新建 my_form/my_form.vue

在其他组件,跳转到 my_form.vue 页面:

bindCard(){
    this.$router.push('/my_form/my_form')
}

在 my_form.vue 页面,通过 auth_token 去请求数据,然后拼接数据,页面自动提交表单。

my_form.vue:

<template>
    <div>
        <form name="autoJumpForm" method="post" :action="bindCardObj.requestFrontUrl"
        v-if="bindCardObj" >
            <input type="hidden" name="version" id="version" :value="bindCardObj.version" />
            <input type="hidden" name="encoding" id="encoding" :value="bindCardObj.encoding" />
            <input type="hidden" name="signMethod" id="signMethod" :value="bindCardObj.signMethod" />
            <input type="hidden" name="txnType" id="txnType" :value="bindCardObj.txnType" />
            <input type="hidden" name="txnSubType" id="txnSubType" :value="bindCardObj.txnSubType" />
            <input type="hidden" name="bizType" id="bizType" :value="bindCardObj.bizType" />
            <input type="hidden" name="channelType" id="channelType" :value="bindCardObj.channelType" />
            <input type="hidden" name="accessType" id="accessType" :value="bindCardObj.accessType" />
            <input type="hidden" name="acqInsCode" id="acqInsCode" :value="bindCardObj.acqInsCode" />
            <input type="hidden" name="merCatCode" id="merCatCode" :value="bindCardObj.merCatCode" />
            <input type="hidden" name="merName" id="merName" :value="bindCardObj.merName" />
        </form>
    </div>
</template>

<script>
    //->去请求绑卡接口, 只需要auth-token
    import { bindCard } from "../../api/common_pay";
    
    export default {
        name: "my_form",
        data(){
            return {
                bindCardObj: {}
            }
        },
        beforeCreate() {
            //->去调取绑卡的接口
            //->不需要拼接参数
            bindCard().then(data => {
                console.log(data.data)
                this.bindCardObj = data.data
            }, err => {
                
            })
        },
        mounted(){
            // 去提交form表单
            this.$nextTick(() => {
                setTimeout(() => {
                    document.autoJumpForm.submit()
                }, 100)
            })
        }
    }
</script>

9. 关于 checkbox 和 Radio

终于搞清楚了, 两个互不相干的 checkbox, 要做到互斥的功能,只能通过双向绑定 v-model 的值,去设置 checkbox,是否选中。

实际例子:

<pax-cell-group title="" class="">
    <pax-cell-item type="div" href="javascript:;" @click.native="list_toggle_wechat">
        <span slot="left">
            <pax-checkbox v-model="checkbox_A"
                shape="circle"
                @click.native.stop
                size="30"
                :change="myFunc_A" >
                <img src="/images/wechat.png" />微信支付
            </pax-checkbox>
        </span>
        <span slot="right"></span>
    </pax-cell-item>
    <pax-cell-item type="div" href="javascript:;" @click.native="list_toggle_QPAY">
        <span slot="left">
            <pax-checkbox v-model="checkbox_B"
                shape="circle"
                @click.native.stop
                size="30"
                :change="myFunc_B" >
                <img src="/images/quick-payment.png" />快捷支付
            </pax-checkbox>
        </span>
        <span slot="right"></span>
    </pax-cell-item>
</pax-cell-group>

<script>
    export default {
        data(){
            return {
                checkbox_A: true,
                checkbox_B: false
            }
        },
        methods: {
            list_toggle_wechat (e) {
                // 点击 list
            },
            list_toggle_QPAY (e) {
                // 点击 list
            },
            myFunc_A (e) {
                var that = this
                if (that.checkbox_A === true) {
                    // 表示已选择 微信支付
                    //-> 去取消 快捷支付 的选中
                    that.checkbox_A = false
                    that.checkbox_B = true
                } else {
                    that.checkbox_A = true
                    that.checkbox_B = false
                }
            },
            myFunc_B (e) {
                var that = this
                if (that.checkbox_B === true) {
                    // 表示已选择 快捷支付
                    //-> 去取消 微信支付 的选中
                    that.checkbox_A = true
                    that.checkbox_B = false
                } else {
                    that.checkbox_A = false
                    that.checkbox_B = true
                }
            }
        }
    }
</script>

在 点击 checkbox 或者 Radio 的时候,会触发 list,
所以, 会弹出两次 12,
所以, 要阻止事件冒泡, 阻止事件向上传播
在 checkbox 或者 Radio 上加上 @click.native.stop 就可以了

10. js 去触发表单提交

js 去触发 checkbox 点击选中

<VCheckbox id="QPAY" v-model="checkVal" @click.native.stop></VChexkbox>
document.getElementById('QPAY').click()

js 去触发表单提交

<form name="autoJumpForm" method="post"></form>
document.autoJumpForm.submit()