初学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;
}
}
}