Vue2中Tabbar案例
1.搭建项目目录
- mytabs.vue:页面组件
- myheader.vue:头部组件
- mynavbar.vue:底部导航栏
- mygoods.vue:商品列表
- mysearch.vue:搜索
- myinfo.vue:我的信息
- mytable.vue:表格封装
2.myheader.vue组件的封装
<template>
<div class="Myheader" :style="{ backgroundColor: background, color }">{{ title }}</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
background: {
type: String,
default: '#ccc'
},
color: {
type: String,
default: '#fff'
}
}
}
</script>
<style lang="less" scoped>
.Myheader {
height: 45px;
background-color: rgb(0, 140, 255);
text-align: center;
line-height: 45px;
color: #fff;
}
</style>
3.底部导航栏动态渲染
<template>
<div class="tabscontainer">
<div class="tabitem"
v-for='(value,index) in list'
:key='value.text'>
<span :class="['iconfont',value.icon]"></span>
<span>{{value.text}}</span>
</div>
</div>
</template>
<script>
export default {
props: {
list: {
type: Array,
required: true,
validator (value) {
if (value.length < 2 || value.length > 5) {
return false
} else {
return true
}
}
}
}
}
</script>
4.数据模拟
data() {
return {
comName: 'MyGoods',
navs: [
{ id: 1, icon: 'icon-a-topliontubiaoku_gengduoguanli', text: '商品列表', comname: 'MyGoods' },
{ id: 2, icon: ' icon-a-topliontubiaoku_sousuo', text: '商品搜索', comname: 'MySearch' },
{ id: 3, icon: 'icon-a-topliontubiaoku_denglutouxiang', text: '我的信息', comname: 'MyInfo' }
]
}
},
5.使用父传子传递数据
<!-- 底部栏 -->
<mynavbar :list='tablist'></mynavbar>
6.导航栏功能的实现
<template>
<div>
<!-- 头部区域 -->
<Myheader title="我的Tabs" background="skyblue" color="white"></Myheader>
<!-- 动态组件区域 -->
<component :is="comName"></component>
<!-- 底部区域 -->
<MyNavbar @exchange="exchange" :options="navs"></MyNavbar>
</div>
</template>
<script>
import Myheader from './Myheader.vue'
import MyNavbar from './Mynavbar.vue'
import MyGoods from './MyGoods.vue'
import MySearch from './MySearch.vue'
import MyInfo from './MyInfo.vue'
export default {
components: {
Myheader,
MyNavbar,
MyGoods,
MySearch,
MyInfo
},
data() {
return {
comName: 'MyGoods',
navs: [
{ id: 1, icon: 'icon-a-topliontubiaoku_gengduoguanli', text: '商品列表', comname: 'MyGoods' },
{ id: 2, icon: ' icon-a-topliontubiaoku_sousuo', text: '商品搜索', comname: 'MySearch' },
{ id: 3, icon: 'icon-a-topliontubiaoku_denglutouxiang', text: '我的信息', comname: 'MyInfo' }
]
}
},
methods: {
exchange(name) {
this.comName = name
}
}
}
</script>
<style lang="less" scoped>
@import url('//at.alicdn.com/t/font_3259223_o7dt2dtyk6p.css');
</style>
7.ajax的封装
1.在src文件夹下新建一个utils文件夹,在utils文件夹中新建一个request.js文件并在其实配置基准路径
import axios from 'axios'
axios.defaults.baseURL = 'https://applet-base-api-t.itheima.net/'
export default axios
2.在src文件夹下新建一个apis文件夹,在apis文件夹下新建一个getGoods.js文件在该文件中配置方法
import axios from '@/utils/request'
export function getGoodList() {
return axios({
url: '/api/goods'
})
}
3.在MyGoods.vue文件夹中发起ajax请求并将数据传递给MyTable.vue组件
created() {
getGoodList().then(res => {
if (res.status == 200) {
this.list = res.data.data
}
})
},
data() {
return {
list: []
}
},
//在MyTable.vue组件中
props: {
Goodslist: {
type: Array,
required: true
}
}
// 在MyGoods.vue组件中
<Mytable :Goodslist="list"></Mytable>
8.实现商品列表的渲染
1.标题可以使用具名插槽,让使用者决定到底渲染哪些数据
// 在MyTable.vue中定义具名插槽
<thead>
<tr>
<slot name="thead"></slot>
</tr>
</thead>
2.在MyGoods组件中封装结构并写入具名插槽中
<template #thead>
<th scope="col">#</th>
<th scope="col">商品名称</th>
<th scope="col">商品价格</th>
<th scope="col">标签</th>
<th scope="col">操作</th>
</template>
3.数据渲染可以使用 作用域插槽 让使用者决定数据的渲染格式
<tbody>
<tr v-for="(item, index) in Goodslist">
<slot name="tbody" :row="item" :index="index"></slot>
</tr>
</tbody>
4.在MyGoods组件中拿到作用域插槽传递过来的数据并实现渲染
<template #tbody="{ row, index }">
<td>{{ index + 1 }}</td>
<td>{{ row.goods_name }}</td>
<td>¥{{ row.goods_price }}</td>
<td>
<td>{{row.tags}}</td>
</template>
9.实现Tags的渲染
1.要封装的结构有:按钮,输入框,tags标签
<td>
<input
type="text"
style="width: 100px"
/>
<button class="btn btn-primary btn-sm">+tags</button>
<span class="badge badge-warning" v-for="(item, index) in row.tags" :key="index">{{ item }}</span>
</td>
<td><button class="btn btn-danger btn-sm">删除</button></td>
10.实现Tags的操作
1.单击+tags,显示输入框,同时隐藏当前按钮(v-if)
<input
type="text"
style="width: 100px"
v-if="row.inputVisible"
/>
<button class="btn btn-primary btn-sm" @click="row.inputVisible = true" v-else>+tags</
2.让输入框聚焦
// 在main.js中定义全局自定义指令
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
// 在input标签中直接使用自定义指令实现聚焦
<input
type="text"
style="width: 100px"
v-if="row.inputVisible"
v-focus
/>
<button class="btn btn-primary btn-sm" @click="row.inputVisible = true" v-else>+tags</
3.为输入框添加失焦事件,隐藏输入框,显示按钮
<input
type="text"
style="width: 100px"
v-if="row.inputVisible"
v-focus
@blur="row.inputVisible = false"
/>
4.按下enter键实现tag的添加
说明:
1.添加事件绑定,传入当前行数据对象-row
```vue
<input type="text" style="width: 100px" v-if="row.inputVisible" @blur="row.inputVisible = false" v-focus @keyup.enter="addTag(row)" /> ```
2.添加双向绑定,获取输入框的内容
<input
type="text"
style="width: 100px"
v-if="row.inputVisible"
@blur="row.inputVisible = false"
v-focus
v-model="row.inputValue"
@keyup.enter="addTag(row)"
/>
3.将内容添加到数组
addTag(obj) {
obj.tags.push(obj.inputValue)
}
}
4.修改是否隐藏的状态值
addTag(obj) {
obj.tags.push(obj.inputValue)
obj.inputVisible = false
}
}
5.非空判断
if (obj.inputValue.trim().length == 0) {
alert('输入的标签不能为空')
return
}
6.有必要判断当前添加的tag是否重复,如果重复则不添加
if (obj.tags.indexOf(obj.inputValue) == -1) {
obj.tags.push(obj.inputValue)
obj.inputValue = ''
obj.inputVisible = false
}
7.操作汇总
addTag(obj) {
// 非空判断
if (obj.inputValue.trim().length == 0) {
alert('输入的标签不能为空')
return
}
if (obj.tags.indexOf(obj.inputValue) == -1) {
obj.tags.push(obj.inputValue)
obj.inputValue = ''
obj.inputVisible = false
}
}
8.按下esc键实现输入框清空
@keyup.esc="row.inputValue = ''"
11.实现点击删除按钮实现删除
// 绑定事件
<td><button class="btn btn-danger btn-sm" @click="del(row.id)">删除</button></td>
// 实现删除功能
del(id) {
this.list = this.list.filter(v => v.id != id)
},
12.总结
1️⃣父传子(props的应用)
2️⃣在线使用字体图标
3️⃣动态组件component配合is属性的使用
4️⃣子传父($emit)
5️⃣动态绑定样式
6️⃣ajax的封装
7️⃣具名插槽以及作用域插槽的使用
8️⃣自定义指令的使用
9️⃣数组方法的熟练运用
🔟Vue指令的熟练使用