案例--封装一个TabBar组件
在样式里引用资源
// App.vue
<template></template>
<style>
@import './assets/css/base.css';
</style>
初始化结构
App.vue
<template>
<div id="app">
<TabBar></TabBar>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
export default {
name: 'App',
components: {
TabBar
}
}
</script>
<style scoped>
</style>
TabBar.vue
<template>
<div id="tab-bar">
<div class="tab-bar-item">首页</div>
<div class="tab-bar-item">分类</div>
<div class="tab-bar-item">购物车</div>
<div class="tab-bar-item">我的</div>
</div>
</template>
<script>
export default {
name: 'TarBar'
}
</script>
<style scoped>
#tab-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -1px 1px rgba(100, 100, 100,.2);
}
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
}
</style>
TabBar进一步抽离出TarBarItem
由TarBarItem组成,新增一个TarBarItem组件
TarBarItem.vue
<template>
<div class="tab-bar-item">
<img src="../../assets/img/tabbar/home.svg" alt="">
<div>首页</div>
</div>
</template>
<script>
export default {
name: 'TabBarItem'
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
}
</style>
TabBar.vue
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'TarBar'
}
</script>
<style scoped>
#tab-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -1px 1px rgba(100, 100, 100,.2);
}
</style>
App.vue
<template>
<div id="app">
<TabBar>
<TabBarItem></TabBarItem>
<TabBarItem></TabBarItem>
<TabBarItem></TabBarItem>
<TabBarItem></TabBarItem>
</TabBar>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style scoped>
</style>
效果
问题:同一个图片,一样的文字
TarBarItem.vue的内容是写死的吗?
不是,加入具名插槽
TarBarItem.vue
<template>
<div class="tab-bar-item">
<solt name="item-icon"></solt>
<solt name="item-text"></solt>
</div>
</template>
<script>
export default {
name: 'TabBarItem'
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
}
</style>
App.vue
<template>
<div id="app">
<tab-bar>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item>
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style scoped>
</style>
处于激活状态的图片和文字
TabBarItem.vue
新增:一个数据isActive、一个类active
<template>
<div class="tab-bar-item">
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon_active"></slot></div>
<div :class="{active: isActive}"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
data () {
return {
isActive: true
}
}
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
}
.active {
color: lightcoral;
}
</style>
经验:
当插槽有属性时,为了防止使用时覆盖掉slot的属性,一般都是在slot标签外面包一层div,然后那些属性放到div的属性上
例如
这样的插槽被使用时可能会被覆盖掉v-if属性
<slot v-if="!isActive" name="item-icon"></slot>
而这样就不会
<div v-if="!isActive"><slot name="item-icon"></slot></div>
效果
点击每一个item对应一个路由
components文件夹和view的区别
components放的是公共组件
而view放的是单独组件
新建四个组件
在双src文件夹下新建view文件夹,然后分别新建home、category、shopcar、profile文件夹放对应组件
比如
home文件夹下的Home.vue
<template>
<div>首页</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style scoped>
</style>
新增路由
在src文件夹下新建一个router文件夹并在该文件夹下新建一个index.js
index.js
// 1.导入
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2.挂载
Vue.use(VueRouter)
// 懒加载
const Home = () => import('../view/home/Home.vue')
const Category = () => import('../view/Category/Category.vue')
const ShopCar = () => import('../view/shopcar/ShopCar.vue')
const Profile = () => import('../view/profile/Profile.vue')
// 3.创建路由配置对象
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
components: Home
},
{
path: '/category',
components: Category
},
{
path: '/shopcar',
components: ShopCar
},
{
path: '/profile',
components: Profile
}
]
// 4.实例化路由对象
const router = new VueRouter({
routes
})
// 5.默认导出
export default router
main.js导入路由
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 导入组件库
import ElementUI from 'element-ui'
// 导入组件相关样式
import 'element-ui/lib/theme-chalk/index.css'
// 配置Vue插件
Vue.use(ElementUI)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
父组件给子组件传路径
App.vue
<template>
<div id="app">
<router-view></router-view>
<tab-bar>
<tab-bar-item path="/home">
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<img slot="item-icon_active" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category">
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<img slot="item-icon_active" src="./assets/img/tabbar/category_active.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/shopcar">
<img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<img slot="item-icon_active" src="./assets/img/tabbar/shopcart_active.svg" alt="">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile">
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<img slot="item-icon_active" src="./assets/img/tabbar/profile_active.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
<!-- <Login></Login> -->
</div>
</template>
<script>
import TabBar from './components/tabbar/TabBar.vue'
import TabBarItem from './components/tabbar/TabBarItem.vue'
// import Login from './components/Login.vue'
export default {
name: 'App',
components: {
TabBar,
TabBarItem
// Login
}
}
</script>
<style scoped>
</style>
TabBarItem.vue
<template>
<div class="tab-bar-item" @click="itemClick">
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon_active"></slot></div>
<div :class="{active: isActive}"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
path: String
},
data () {
return {
isActive: true
}
},
methods: {
itemClick () {
this.$router.push(this.path)
}
}
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
}
.active {
color: lightcoral;
}
</style>
点击item才激活
将TabBarItem的isActive改成计算属性
computed: {
isActive () {
return this.$route.path.indexOf(this.path) !== -1
}
}
如何让使用者修改激活样式?
比如想修改激活文字样式activeColor="blue"
<tab-bar-item path="/home" activeColor="blue">
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<img slot="item-icon_active" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
先在TabBarItem里添加一个自定义属性activeColor
修改控制文字的那个插槽绑定的样式
<template>
<div class="tab-bar-item" @click="itemClick">
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon_active"></slot></div>
<div :style="activeStyle"><slot name="item-text"></slot></div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
path: String,
activeColor: {
type: String,
default: 'red'
}
},
data () {
return {
}
},
computed: {
isActive () {
return this.$route.path.indexOf(this.path) !== -1
},
activeStyle () {
return this.isActive ? { color: this.activeColor } : {}
}
},
methods: {
itemClick () {
this.$router.push(this.path)
}
}
}
</script>
<style scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
}
</style>