BTabar组件封装(二)
上一篇中提到了在组件封装中的自己还存在的一些缺点,还有一个致命的缺点就是如何在同一个页面中加载我自己需要的不同的页面的问题。
其实可以使用多个页面代码,全部封装到一个页面中,然后用display属性来控制是否显示。
这样,对于使用者来说,就不太友好了。不过,还是找到了解决方案:uni-app中自定义动态底部tabbar(附示例源码)
摘抄一下思想:
- 将自定义TabBar所需的几个页面作为组件加载进来(如,index.vue),代码逻辑控制该页面显示与否
- 将自定义tabbar写到index.vue中或将其封装为组件加载进来
- 使用vuex统一管理数据
使用vuex统一管理数据,也就是在vue根文件中注册store,这样所有的组件都可以使用store中的数据了,使用方法也很简单,就是使用计算属性返回store中的数据到一个新属性上,然后在你模板中则可以使用这个属性值了。
在使用store的时候,定义列表,也不妨定义为这样的配置文件:
"tabBar": {
"borderStyle": "black",
"backgroundColor": "#333",
"color": "#8F8F94",
"selectedColor": "#f33e54",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/img/tabbar/home.png",
"selectedIconPath": "static/img/tabbar/homeactive.png",
"text": "首页"
},
{
"pagePath": "pages/index/index",
"iconPath": "static/img/tabbar/home.png",
"selectedIconPath": "static/img/tabbar/homeactive.png",
"text": "首页"
}]
}
如果使用store配置,这里还是给一个小案例:
目录结构:
index.js文件:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
// 全局变量定义处
state:{
BTabBar: {
borderStyle: "black",
backgroundColor: "#333",
color: "#8F8F94",
selectedColor: "#f33e54",
list: [{
"pagePath": "pages/index/index",
"iconPath": "static/img/tabbar/home.png",
"selectedIconPath": "static/img/tabbar/homeactive.png",
"text": "首页"
},
{
"pagePath": "pages/index/index",
"iconPath": "static/img/tabbar/home.png",
"selectedIconPath": "static/img/tabbar/homeactive.png",
"text": "首页"
}
],
},
currentIndex: 0
},
// 全局方法定义处
mutations:{
}
});
export default store;
在项目目录下的main.js文件中导入这个index.js文件并声明方法,在这个index.js文件中的变量和方法才能在各个页面使用并生效。
在main.js中导入:
import Vue from 'vue'
import App from './App'
// 1. 导入index.js
import store from './store/index.js'
Vue.config.productionTip = false
// 2. 全局挂载
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
store, // 3. 声明
...App
})
app.$mount()
由于要对点击的项目的判断,这里需要监听定义的currentIndex属性。先在使用页面,导入我们需要的mapState和mapMutations ,可以分别在computed计算属性方法中使用mapState对全局变量进行监控,在method中使用mapMutations进行全局方法监控。
注释:
- mapState作用:可以辅助获得多个state的值,即获取多个定义的属性值
对于定义的变量,我们该如何接受呢?其实有两种方式:
- 使用data接收
- 使用computed接收
那么,两者有什么区别?
其实,如果你用data去接收$store.state,这只是一个简单的赋值操作,因此state中的状态改变的时候不能被vue中的data监听到;
故而一般用computed去接收state中的值。两种写法如下(类似,区别在于地方):
data () {
return {
dataCount: this.$store.state.count //用data接收
}
},
computed:{
count(){
return this.$store.state.count //用computed接收
}
}
当我们使用computed来设置属性的时候,vue可以监听到数据的变化,但是我们又该如何来改变它的值?下面做一个简单的测试案例:
项目结构还是使用store/index.js,然后在main.js中三步配置,配置好了后,下面就是测试的页面:
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{ test }}</text>
</view>
<button type="primary" @click="change">修改</button>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
computed: {
// 定义的属性test,如果需要动态修改,就需要设置get和set方法
// 否则报错:Computed property "test" was assigned to but it has no setter.
test:{
get(){
console.log(this.$store.state.currentIndex);
return this.$store.state.currentIndex;
},
set(val){
this.$store.state.currentIndex = 123;
}
}
},
methods: {
change:function(){
this.test = 234;
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
效果: