vuejs2-4 header.vue组件开发
1 简单图解

2 src/App.vue
<template>
<div>
<v-header :seller="seller"></v-header>
<!--路由切换区域-->
<div class="tab">
<div class="tab-item">
<router-link to="/goods" :seller="seller">商品</router-link>
</div>
<div class="tab-item">
<router-link to="/ratings" :seller="seller">评论</router-link>
</div>
<div class="tab-item">
<router-link to="/seller" :seller="seller">商家</router-link>
</div>
</div>
<!--路由内容区域-->
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
<!--
'router-link'
Vuejs2+版本写法 会被解析成<a></a>
to="/xxx"指向的路由地址(src/main.js配置的路由一致)
'keep-alive' 组件间切换时保存组件的信息到内存中,切换回来时仍然是之前的状态
'router-view' 路由渲染视图
:seller="seller" 父组件向子组件传递自定义名称的数据
-->
<script>
import header from 'components/header/header.vue'; // 引入header组件
import {urlParse} from 'common/js/urlParse';
// 引入urlParse.js文件 window.loacation.search操作
const ERR_OK = 0;
export default {
data() {
return {
seller: {
id: (() => {
let queryParam = urlParse(); // 获取地址中的查询字符串
return queryParam.id;
})()
}
};
},
created() {
let url = '/api/seller?id=' + this.seller.id;
this.$http.get(url).then((response) => {
response = response.body;
if (response.errno === ERR_OK) {
console.log(response);
this.seller = Object.assign({}, this.seller, response.data);
}
});
},
components: { // 注册header组件
'v-header': header
}
};
</script>
<style lang="stylus">
@import "./common/stylus/mixin.styl"
.tab
display: flex
width: 100%
height: 40px
line-height: 40px
border-1px(rgba(7, 17, 27, 0.1))
.tab-item
flex: 1
text-align: center
& > a
display: block
font-size: 14px
color: rgb(77, 85, 93)
&.active
color: rgb(240, 20, 20)
</style>
3 src/header.vue
<template>
<div class="header">
<!-- 商品信息 -->
<div class="content-wrapper">
<div class="avatar">
<img alt="" height="64" width="64" :src="seller.avatar">
</div>
<div class="content">
<div class="title">
<span class="brand"></span>
<span class="name">{{seller.name}}</span>
</div>
<div class="description">
{{seller.description}}/{{seller.deliveryTime}}分钟送达
</div>
<div v-if="seller.supports" class="support">
<span class="icon" :class="classMap[seller.supports[0].type]"></span>
<span class="text">{{seller.supports[0].description}}</span>
</div>
</div>
<div v-if="seller.supports" class="support-count" @click="showDetail(1)">
<span class="count">{{seller.supports.length}}个</span>
<i class="icon-keyboard_arrow_right"></i>
</div>
</div>
<!-- 公告 -->
<div class="bulletin-wrapper" @click="showDetail(1)">
<span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span>
<i class="icon-keyboard_arrow_right"></i>
</div>
<!--背景图片-->
<div class="bg">
<img :src="seller.avatar" width="100%" height="100%" alt="">
</div>
<!--公告详情-->
<!--transition用法变化 css使用变化-->
<transition name="fade">
<div v-show="detail_show" class="detail">
<div class="detail-wrapper clearfix">
<div class="detail-main">
<h1 class="name">{{seller.name}}</h1>
<div class="star-wrapper">
<star :size="48" :score="seller.score"></star>
</div>
<div class="title">
<div class="line"></div>
<div class="text">优惠信息</div>
<div class="line"></div>
</div>
<ul class="supports" v-if="seller.supports">
<li v-for="(item,index) in seller.supports" class="supports-item">
<span class="icon" :class="classMap[seller.supports[index].type]"></span>
<span class="text">{{seller.supports[index].description}}</span>
</li>
</ul>
<div class="title">
<div class="line"></div>
<div class="text">商家公告</div>
<div class="line"></div>
</div>
<div class="bulletin">{{seller.bulletin}}</div>
</div>
</div>
<div class="detail-close">
<i class="icon-close" @click="showDetail(0)"></i>
</div>
</div>
</transition>
</div>
</template>
<script type="text/ecmascript-6">
import star from 'components/star/star'; // 引入star组件
export default{
props: { // 获取父组件传递过来的数据seller
seller: {
type: Object
}
},
data() { // Vue 实例的数据对象
return {
detail_show: false
};
},
methods: {
// methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。
// 方法中的 this 自动绑定为 Vue 实例
showDetail: function (action) { // 点击显示或隐藏公告详情
if (action) {
this.detail_show = true;
} else {
this.detail_show = false;
}
}
},
created() {
// 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:
// 数据观测(data observer),属性和方法的运算, watch/event 事件回调。
// 然而,挂载阶段还没开始,$el 属性目前不可见。
this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];
},
components: {
// 注册组件 1引入2注册,这样组件才能被使用
star
}
};
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import "../../common/stylus/mixin"
.header
$col = #fff
$bg = rgba(7,17,27,0.5)
$pad_top = 24px
color:$col
background:$bg
position:relative
overflow:hidden
.content-wrapper
padding:$pad_top 12px 18px $pad_top
font-size:0 /*紧贴*/
position:relative
.avatar
display: inline-block
vertical-align:top
img
border-radius:2px
.content
margin-left:16px
display:inline-block
font-size:14px
.title
margin:2px 0 8px 0
.brand
display:inline-block
vertical-align:top /*图片与文字顶部对齐*/
width:30px
height:18px
bg-img("brand") /*按需加载2x1 3x*/
background-size:30px 17px
background-repeat:no-repeat
.name
margin-left:6px
font-size:16px
color:rgb(255,255,255)
line-height:18px
font-weight:bold
.description
margin-bottom:10px
font-size:12px;
color: rgb(255,255,255)
line-height:12px
.supports
.icon
display:inline-block
width:12px
height:12px
margin-right:4px
background-size:12px 12px
background-repeat: no-repeat
vertical-align:top
&.decrease
bg-img("decrease_1")
&.discount
bg-img("discount_1")
&.invoice
bg-img("invoice_1")
&.special
bg-img("special_1")
&.guarantee
bg-img("guarantee_1")
.text
display:inline-block
font-size:10px
color:rgb(255,255,255)
line-height:12px;
.support-count
position:absolute
right:12px
bottom:18px
height:24px
color:rgb(255,255,255)
line-height:24px
background:rgba(0,0,0,.2)
padding:0px 8px
text-align:center
border-radius:12px
.count
vertical-align:top
font-size:10px
.icon-keyboard_arrow_right
font-size:10px
line-height:24px
margin-left:2px
.bulletin-wrapper
height:28px
line-height:28px
padding:0 22px 0 12px
white-space: nowrap
overflow:hidden
text-overflow:ellipsis
position:relative
background-color:rgba(7,17,27,.2)
.bulletin-title
display:inline-block
height:12px
width:22px
bg-img('bulletin')
background-size:22px 12px
background-repeat:no-repeat
vertical-align:top
margin-top:8px
.bulletin-text
font-size:10px
margin:0 4px
vertical-align:top
.icon-keyboard_arrow_right
position:absolute
top:8px
right:12px
font-size:10px
.bg
position:absolute
left:0
top:0
width:100%
height:100%
z-index:-1
filter: blur(10px)
.detail
position:fixed
left:0
top:0
z-index:100
width:100%
height:100%
overflow:auto
opacity: 1
background: rgba(7, 17, 27, 0.8)
backdrop-filter: blur(10px)
&.fade-enter-active,&.fade-leave-active
transition:all 0.5s
&.fade-enter,&.fade-leave-active
opacity:0
background:rgba(7,17,27,0)
.detail-wrapper
min-height:100%
.detail-main
margin-top:64px
padding-bottom:64px
.name
font-size:16px
font-weight:700
color:rgb(255,255,255)
line-height:16px
text-align:center
.star-wrapper
margin-top:18px
padding:2px 0
text-align:center
.title
display:flex
width:80%
margin:30px auto 24px auto
.line
flex:1
position:relative
top: -6px
border-bottom: 1px solid rgba(255,255,255,.2)
.text
padding:0 12px
font-weight:700
font-size:14px
.supports
width:80%
margin:0 auto
.supports-item
padding:0 12px
margin-bottom: 12px
font-size:0
&:last-child
margin-bottom:0
.icon
display:inline-block
width:16px
height:16px
margin-right:6px
background-size:16px
background-repeat:no-repeat
vertical-align:top
&.decrease
bg-img("decrease_2")
&.discount
bg-img("discount_2")
&.invoice
bg-img("invoice_2")
&.special
bg-img("special_2")
&.guarantee
bg-img("guarantee_2")
.text
font-size:12px
font-weight:200
color: rgb(255,255,255)
line-height:16px
.bulletin
width:80%
margin:0 auto
font-size:12px
font-weight:200
color: rgb(255,255,255)
line-height:24px
.detail-close
position: relative
width:32px
height:32px
margin:-64px auto 0 auto
clear:both
font-size:32px
</style>

4 使用star组件
<!--并传递两个属性size score给star组件--> <star :size="48" :score="seller.score"></star>
5 star组件 src/components/star.vue
<template>
<div class="star" :class="starType">
<span v-for="(itemClass,index) in itemClasses" :class="itemClass"
class="star-item" v-bind:key="itemClass.index"></span>
</div>
</template>
<!--使用v-for遍历提示加上key区别tra-->
<script type="text/ecmascript-6">
const LENGTH = 5; // 假设总共有五位
const CLS_ON = 'on'; //
const CLS_HALF = 'half';
const CLS_OFF = 'off';
export default {
props: { // 接收header.vue以属性传递过来的数据
size: {
type: Number
},
score: {
type: Number
}
},
computed: { // 计算属性
starType() {
return 'star-' + this.size;
},
itemClasses() {
let result = [];
let score = Math.floor(this.score * 2) / 2; // 保证是整数或是x.5的小数 向下取整(4.9、4.1==>4)
let hasDecimal = score % 1 !== 0;
let integer = Math.floor(score); // 整数或 x.5小数都取整
for (let i = 0; i < integer; i++) { // 每位添加全星
result.push(CLS_ON); // ['on','on']
};
if (hasDecimal) { // x.5的小数 末尾有星星的位添加一个半心
result.push(CLS_HALF); // ['on','on', 'half']
};
while (result.length < LENGTH) { // 剩下的空星位用空星补齐
result.push(CLS_OFF); // ['on','on', 'half', 'off', 'off', 'off']
};
return result;
}
}
};
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import "../../common/stylus/mixin"
.star
font-size: 0
.star-item
display: inline-block
background-repeat: no-repeat
&.star-48
.star-item
width:20px
height:20px
margin-right:22px
background-size: 20px 20px
&:last-child
margin-right:0
&.on
bg-img('star48_on')
&.half
bg-img('star48_half')
&.off
bg-img('star48_off')
&.star-36
.star-item
width:15px
height:15px
margin-right:8px
background-size: 15px 15px
&:last-child
margin-right:0
&.on
bg-img('star36_on')
&.half
bg-img('star36_half')
&.off
bg-img('star36_off')
&.star-24
.star-item
width:10px
height:10px
margin-right:3px
background-size: 10px 10px
&:last-child
margin-right:0
&.on
bg-img('star24_on')
&.half
bg-img('star24_half')
&.off
bg-img('star24_off')
</style>

浙公网安备 33010602011771号