初學vue已近3個周,至此開發技能已滿足。從eggjs 到 vue 再到 scss,這個過程需要總結和分享。深度學習
需要從這裏點點滴滴的開始 ~
以上截圖是,剛爲內容分享使用vue所畫的頁面。看效果,與原圖相比逼真度——真假難分
接下來總結方向,vue中如何自定義組件?如何使用自定義組件?
使用自定義組件必然會牽扯到組件間通訊,怎麼實現通訊?
好,上代碼
<!-- @/views/Bank-Acc-Transfer.vue-->
<template>
<div class="acc-transfer-container">
<div class="header">
<div class="img-back">
<span class="img"></span>
</div>
<div class="span">
<span>賬戶轉賬</span>
</div>
</div>
<div class="transfer-list">
<div class="line-row">
<span class="span-left line-height">收款賬戶</span>
<div class="income">
<span class="income-word">{{payee}}</span>
<span class="transfer-img"></span>
</div>
</div>
<div class="line-row line-height">
<span class="span-left">幣種</span>
<span id="r-span">{{currency}}</span>
</div>
<div class="line-row">
<span class="span-left">轉賬金額</span>
<input
type="text"
class="transfer-num"
ref="infocus"
maxlength="16"
autofocus="autofocus"
@blur.prevent="onblur"
@focus="onFocus"
v-model="transferNum"
style="border:1px solid transparent; outline:none; text-align: right"
/>
<div v-if="transferNum ? true : false" @click="resetInput">
<i class="ic_closes"></i>
</div>
<el-button style="padding: 8px 6px" type="danger">全額轉入</el-button>
</div>
<div class="capital-num">
<span class="ctextw">{{textw}}</span>
<span class="ctextm">{{textm}}</span>
</div>
<div class="line-row pay-acc line-height">
<span class="span-left">付款賬戶</span>
<div class="pay">
<span class="pay-word" ref="payWord">{{payAcc}}</span>
<span class="transfer-img"></span>
</div>
</div>
<div class="line-row line-height">
<span id="remain" class="span-left">可用餘額</span>
<span id="m-remain">{{allBalance}}</span>
</div>
</div>
<el-button type="danger" round size="medium" class="btn_next">下一步</el-button>
</div>
</template>
<script>
export default {
... ...
};
</script>
<style lang='scss'>
... ...
</style>
上面代碼看着很不友好,代碼難以閱讀!接下來對上面代碼進行重構,使用組件化拼接方式來實現相同頁面效果。
因爲使用組件化方式,會更加直觀,效果圖及方案設計如圖 ~
以上截圖的設計結構,編碼如下
<!-- @/views/Bank-Acc-Transfer-c.vue-->
<template>
<div class="acc-transfer-container">
<div class="header">
<div class="img-back">
<span class="img"></span>
</div>
<div class="span">
<span>賬戶轉賬</span>
</div>
</div>
<div class="transfer-list">
<li-acc-click mType="收款賬戶" :account="payee" ></li-acc-click>
<li-show mType="幣種" :allBalance="currency" ></li-show>
<li-acc-input :callbackInput="callbackInput"></li-acc-input>
<li-acc-click mType="付款賬戶" :account="payAcc"></li-acc-click>
<li-show :allBalance="allBalance"></li-show>
</div>
<el-button type="danger" round size="medium" class="btn_next">下一步</el-button>
</div>
</template>
<script>
import LiShow from '@/components/LiShow';
import LiAccClick from '@/components/LiAccClick';
import LiAccInput from '@/components/LiAccInput';
export default {
data() {
return {
allBalance: "9.98",
payAcc: "62284806221890098",
currency: "人民幣",
mType: "幣種",
payee: "請選擇"
};
},
mounted() {},
methods: {
handleChange(value) {},
callbackInput(trans_acc = '0.0'){
console.log('實時打印回調-子組件動態輸入的內容>>>', trans_acc)
}
},
components: {// 局部註冊自定義組件
LiShow,LiAccClick,LiAccInput
}
};
</script>
<style lang='scss'>
... ...
</style>
自定義組件 步驟很簡單,其實我們看到的VUE頁面,本身也是一個組件。這個和react-native[react]的組件化思想基本一致。
自定義組件,與vue頁面組件結構一致,同樣分爲三塊:<template> 、 <script> 、 <style scoped lang="scss">
只是在編寫自定義組件時,組件所需大多數用來展示的動態值,均從所植入的頁面組件或組件中獲得!這就涉及到了組件間的通訊~
以此爲例,@/views/Bank-Acc-Transfer-c.vue
中第15行植入的子組件 <li-acc-input :callbackInput="callbackInput"></li-acc-input>
其中<template>
模塊組織編碼顯示組件框架
<template>
<div class="li-acc-input">
<div class="line-row">
<span class="title">{{mType}}</span>
<input
type="text"
ref="infocus"
v-model="transferNum"
maxlength="16"
autofocus="autofocus"
@blur.prevent="onblur"
@focus="onFocus"
/>
<div v-if="transferNum ? true : false" @click="resetInput">
<i class="ic_closes"></i>
</div>
<el-button style="padding: 8px 6px" type="danger" @click="transferAll">全額轉入</el-button>
</div>
<div class="capital-num">
<span class="ctextw">{{textw}}</span>
<span class="ctextm">{{textm}}</span>
</div>
</div>
</template>
代碼中可看到插值 {{mType}} 、{{allBalance}} 以及方法{{callbackInput}},他們三個值和方法回調是由外界傳入的,是props中的字段,是外界[外部組件]與該組件進行通訊的媒介。想要改變他們,讓外界傳入就好。且他們很特殊,組件通訊的字段是在 props: {…} 中做了聲明。組件其餘普通變量transferNum、clickReset、textw和textm,會在data(){…} 中做定義。而區別就是定義的位置 props:{} 和 data(){}
決定了他們的性質 !
<script>
模塊定義該自定義組件的props[用來進行組件間通訊的屬性],和交互邏輯
<script>
export default {
name: "li-acc-input",
data() {
return {
transferNum: "",
clickReset: false,
textw: "",
textm: ""
};
},
watch: {
transferNum(nInput, oInput) {
this.callbackInput(nInput)
if (nInput.indexOf(",") > 0) {
return;
}
}
},
methods: {
transferAll() {
this.transferNum = "100";
},
onblur() {
let thisRef = this;
},
onFocus() {},
resetInput() {
this.clickReset = true;
this.transferNum = "";
this.$refs.infocus.focus();
}
},
props: {
allBalance: {
type: String,
default: "0.00",
required: true
},
mType: {
type: String,
default: "轉賬金額",
required: true
},
callbackInput: {
type: Function
}
}
};
</script>
從上面業務邏輯來看,當用戶輸入轉賬金額時,由於Input標籤使用了雙向綁定 v-model=“transferNum” ,轉賬金額的變量transferNum就會實時發生變化。清除金額的按鈕圖標則會根據表達式 v-if=“transferNum ? true : false” 進行顯示和隱藏。在輸入金額的同時通過 watch
對 transferNum 的監聽,則會實時調用方法 this.callbackInput(nInput),並將輸入的金額通過該方法回調到外組件[父組件]。爲我們頁面進行接口請求,做足數據準備。
<style scoped lang="scss">
模塊則組織該組件如何顯示的樣式
<style scoped lang="scss">
body {
padding: 0 0;
margin: 0 0;
}
.li-acc-input {
background-color: white;
display: block;
border-top: 1px #e3e3e4 solid;
padding: 0 16px;
white-space: nowrap;
overflow: hidden;
}
... ...
</style>
**使用,怎麼在頁面中使用?有兩種方式**
方式一
局部組件註冊,只要三步,
- 如上源代碼 @/views/Bank-Acc-Transfer-c.vue 第27行,
<script>
中引入該自定義組件; - 如上源代碼 @/views/Bank-Acc-Transfer-c.vue 第46-47行,
<script>
中註冊該自定義組件; - 如上源代碼 @/views/Bank-Acc-Transfer-c.vue 第15行,
<templet>
中植入該自定義組件;
方式二
全局組件註冊,只要三步,
- 定義一個js文件,並使用vue方法install進行註冊
/**單個組件的全局註冊 */
// @components/index.js
import LiAccInput from '@/components/LiAccInput.vue'
const components = {
// install 方法是vue中默認的一個方法
install: function(Vue) {
Vue.component('li-acc-input', LiAccInput)
}
}
export default components;
/**多個組件的全局註冊 */
// @components/index.js
import LiAccInput from '@/components/LiAccInput.vue'
import LiAccClick from '@/components/LiAccClick.vue'
import LiShow from '@/components/LiShow.vue'
const components = {
// install 方法是vue中默認的一個方法
install: function(Vue) {
Vue.component('li-acc-input', LiAccInput)
Vue.component('li-acc-click', LiAccClick)
Vue.component('li-show', LiShow)
}
}
export default components;
- main.js中引入並使用Vue.use(),將自定義組件全局代入
/**單個組件的全局註冊 */
// main.js
import Vue from 'vue'
... ...
import LiAccInput from './components/index';
Vue.use(LiAccInput)
... ...
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
/**多個組件的全局註冊,註冊方式不會變 */
// main.js
import Vue from 'vue'
... ...
import Elemnts from './components/index';
Vue.use(Elemnts)
... ...
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
- 在
<templet>
模板中直接植入。結果與方式 一
,一模一樣。且是全局性質~
/** 已註冊的全局單個組件,植入 */
<li-acc-input :callbackInput="callbackInput"></li-acc-input>
/** 已註冊的全局多個組件,植入 */
<div class="transfer-list">
<li-acc-click mType="收款賬戶" :account="payee" ></li-acc-click>
<li-show mType="幣種" :allBalance="currency" ></li-show>
<li-acc-input :callbackInput="callbackInput"></li-acc-input>
<li-acc-click mType="付款賬戶" :account="payAcc"></li-acc-click>
<li-show :allBalance="allBalance"></li-show>
</div>
上截圖中用到了組件間的通訊:**父組件與子組件通訊**
父組件:
Bank-Acc-Transfer-c.vue
子組件:
LiAccInput.vue
**交互一:**
子組件顯示內容,如字段mType,是組件左邊的標籤span展示插值字段。可由外界的父組件動態傳入,
<li-show mType="幣種" :allBalance="currency" ></li-show>
也可以是使用本身設置的默認 props:{…default:‘xx’…} 值;
**交互二:**
子組件的綁定屬性callbackInput,是父組件傳入子組件的方法。
<li-acc-input :callbackInput="callbackInput"></li-acc-input>
在父組件實時回調,並打印子組件傳進來的值trans_acc
methods: {
handleChange(value) {},
callbackInput(trans_acc = '0.0'){ // 這裏會有方法的回調
console.log('實時打印回調-子組件動態輸入的內容>>>', trans_acc)
}
}
父組件能夠實時回調,全憑子組件對標籤Input雙向綁定變量transferNum
的監聽
watch: {
transferNum(nInput, oInput) {
this.callbackInput(nInput) // 就是這裏,執行調用父組件的方法
if (nInput.indexOf(",") > 0) {
return;
}
}
}