07-订单管理-tabs组件
目的:封装一个高可用tabs组件
大致步骤:
xtx-tabs
组件容器 可以有多个xtx-tabs-panel
组件面板xtx-tabs-panel
需要暴露 标题props.label
,名称props.name
,内容<slot />
xtx-tabs
组件组织结构,控制点击事件,标签页激活。
铺垫知识:
jsx
语法,需要简单了解其基本使用 https://cn.vuejs.org/v2/guide/render-function.html
render () {
const name = 'tom'
return <h3>{name}</h3>
}
落的代码:
src/components/library/xtx-tabs.vue
<script>
import { useVModel } from '@vueuse/core'
import { provide } from 'vue'
export default {
name: 'XtxTabs',
props: {
modelValue: {
type: String,
default: ''
}
},
setup (props, { emit }) {
const activeName = useVModel(props, 'modelValue', emit)
// 给xtx-tabs-panel传值
provide('activeName', activeName)
// 点击选项卡对应的处理函数
const tabClick = (name, index) => {
activeName.value = name
// 触发一个点击自定义时间
emit('tab-click', { name, index })
}
return { activeName, tabClick }
},
render () {
// jsx语法,它能够让我们创建节点和写html一样
// 1. 动态插值表达式{} 2. 尽量三元表示式做判断,使用map来遍历 3.事件使用原始方式绑定
// 默认插槽节点
const panels = this.$slots.default()
console.log(panels)
// 选项卡
const nav = (
<nav>
{panels.map((item, i) => {
return (
<a
onClick={() => this.tabClick(item.props.name, i)}
class={{ active: item.props.name === this.activeName }}
href="javascript:;"
>
{item.props.label}
</a>
)
})}
</nav>
)
return <div class="xtx-tabs">{[nav, panels]}</div>
}
}
</script>
<style lang="less">
.xtx-tabs {
background: #fff;
> nav {
height: 60px;
line-height: 60px;
display: flex;
border-bottom: 1px solid #f5f5f5;
> a {
width: 110px;
border-right: 1px solid #f5f5f5;
text-align: center;
font-size: 16px;
&.active {
border-top: 2px solid @xtxColor;
height: 60px;
background: #fff;
line-height: 56px;
}
}
}
}
</style>
src/components/library/xtx-tabs-panel.vue
<template>
<!-- 装载是内容 -->
<div class="xtx-tabs-panel" v-show="activeName===name">
<slot />
</div>
</template>
<script>
import { inject } from 'vue'
export default {
name: 'XtxTabsPanel',
props: {
// 标签页标题文章
label: {
type: String,
default: ''
},
// 唯一标识
name: {
type: String,
default: ''
}
},
setup () {
// 当前组件该不该显示,取决于xtx-tabs组件的activeName数据是否和props.name一样
const activeName = inject('activeName')
return { activeName }
}
}
</script>
<style scoped lang="less"></style>
src/views/member/order/index.vue
<template>
<div class="member-order-page">
<XtxTabs v-model="activeName" @click-tab="clickTab">
<XtxTabsPanel name="all" label="全部订单">全部订单</XtxTabsPanel>
<XtxTabsPanel name="unpay" label="待付款">待付款</XtxTabsPanel>
<XtxTabsPanel name="deliver" label="待发货">待发货</XtxTabsPanel>
<XtxTabsPanel name="receive" label="待收货">待收货</XtxTabsPanel>
<XtxTabsPanel name="comment" label="待评价">待评价</XtxTabsPanel>
<XtxTabsPanel name="complete" label="已完成">已完成</XtxTabsPanel>
<XtxTabsPanel name="cancel" label="已取消">已取消</XtxTabsPanel>
</XtxTabs>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
name: 'MemberOrder',
setup () {
const activeName = ref('all')
const clickTab = (name) => {
console.log(name)
}
return { activeName, clickTab }
}
}
</script>
<style scoped lang="less"></style>
组件升级:
- 弊端,动态生成的xtx-tabs-panel无法正常运行。
- 补丁,动态判断节点类型,组织tabs列表
src/components/library/xtx-tabs.vue
const panels = this.$slots.default()
const dynamicPanels = []
+ panels.forEach(item => {
+ if (item.type.name === 'XtxTabsPanel') {
+ dynamicPanels.push(item)
+ } else {
+ item.children.forEach(com => {
+ dynamicPanels.push(com)
+ })
+ }
+ })
// 选项卡
const nav = (
<nav>
+ {dynamicPanels.map((item, i) => {
src/views/member/order/index.vue
<template>
<div class="member-order-page">
<XtxTabs v-model="activeName">
<XtxTabsPanel
v-for="item in orderStatus"
:key="item.name"
:label="item.label"
:name="item.name"
>{{item.label}}</XtxTabsPanel
>
</XtxTabs>
</div>
</template>
<script>
import { ref } from 'vue'
import { orderStatus } from '@/api/constants'
export default {
name: 'MemberOrderPage',
setup () {
const activeName = ref('all')
return { activeName, orderStatus }
}
}
</script>
<style scoped lang="less"></style>
src/api/constant.js
订单状态常量数据
// 订单状态
export const orderStatus = [
{ name: 'all', label: '全部订单' },
{ name: 'unpay', label: '待付款' },
{ name: 'deliver', label: '待发货' },
{ name: 'receive', label: '待收货' },
{ name: 'comment', label: '待评价' },
{ name: 'complete', label: '已完成' },
{ name: 'cancel', label: '已取消' }
]
08-订单管理-基础布局
目的:完成订单静态布局。
基础样式:
.order-list {
background: #fff;
padding: 20px;
}
.order-item {
margin-bottom: 20px;
border: 1px solid #f5f5f5;
.head {
height: 50px;
line-height: 50px;
background: #f5f5f5;
padding: 0 20px;
overflow: hidden;
span {
margin-right: 20px;
&.down-time {
margin-right: 0;
float: right;
i {
vertical-align: middle;
margin-right: 3px;
}
b {
vertical-align: middle;
font-weight: normal;
}
}
}
.del {
margin-right: 0;
float: right;
color: #999;
}
}
.body {
display: flex;
align-items: stretch;
.column {
border-left: 1px solid #f5f5f5;
text-align: center;
padding: 20px;
> p {
padding-top: 10px;
}
&:first-child {
border-left: none;
}
&.goods {
flex: 1;
padding: 0;
align-self: center;
ul {
li {
border-bottom: 1px solid #f5f5f5;
padding: 10px;
display: flex;
&:last-child {
border-bottom: none;
}
.image {
width: 70px;
height: 70px;
border: 1px solid #f5f5f5;
}
.info {
width: 220px;
text-align: left;
padding: 0 10px;
p {
margin-bottom: 5px;
&.name {
height: 38px;
}
&.attr {
color: #999;
font-size: 12px;
span {
margin-right: 5px;
}
}
}
}
.price {
width: 100px;
}
.count {
width: 80px;
}
}
}
}
&.state {
width: 120px;
.green {
color: @xtxColor;
}
}
&.amount {
width: 200px;
.red {
color: @priceColor;
}
}
&.action {
width: 140px;
a {
display: block;
&:hover {
color: @xtxColor;
}
}
}
}
}
}
基础结构:
<div class="order-list">
<div class="order-item">
<div class="head">
<span>下单时间:2018-01-08 15:02:00</span>
<span>订单编号:62205697599</span>
<span class="down-time">
<i class="iconfont icon-down-time"></i>
<b>付款截止:28分20秒</b>
</span>
</div>
<div class="body">
<div class="column goods">
<ul>
<li v-for="i in 2" :key="i">
<a class="image" href="javascript:;">
<img src="https://yanxuan-item.nosdn.127.net/f7a4f643e245d03771d6f12c94e71214.png" alt="" />
</a>
<div class="info">
<p class="name ellipsis-2">原创设计一体化机身,精致迷你破壁机350mL</p>
<p class="attr ellipsis">
<span>颜色:绿色</span>
<span>尺寸:10寸</span>
</p>
</div>
<div class="price">¥9.50</div>
<div class="count">x1</div>
</li>
</ul>
</div>
<div class="column state">
<p>待付款</p>
</div>
<div class="column amount">
<p class="red">¥19.00</p>
<p>(含运费:¥10.00)</p>
<p>在线支付</p>
</div>
<div class="column action">
<XtxButton type="primary" size="small">立即付款</XtxButton>
<p><a href="javascript:;">查看详情</a></p>
<p><a href="javascript:;">取消订单</a></p>
</div>
</div>
</div>
<div class="order-item">
<div class="head">
<span>下单时间:2018-01-08 15:02:00</span>
<span>订单编号:62205697599</span>
<a href="javascript:;" class="del">删除</a>
</div>
<div class="body">
<div class="column goods">
<ul>
<li>
<a class="image" href="javascript:;">
<img src="https://yanxuan-item.nosdn.127.net/f7a4f643e245d03771d6f12c94e71214.png" alt="" />
</a>
<div class="info">
<p class="name ellipsis-2">原创设计一体化机身,精致迷你破壁机350mL</p>
<p class="attr ellipsis">
<span>颜色:绿色</span>
<span>尺寸:10寸</span>
</p>
</div>
<div class="price">¥9.50</div>
<div class="count">x1</div>
</li>
</ul>
</div>
<div class="column state">
<p>已取消</p>
</div>
<div class="column amount">
<p class="red">¥9.50</p>
<p>(含运费:¥0.00)</p>
</div>
<div class="column action">
<p><a href="javascript:;">查看详情</a></p>
</div>
</div>
</div>
</div>