运用vue-cli和axios实现此项目
app.vue
<template>
<div id="app">
<v-header></v-header>
<div class="main">
<router-view></router-view>
</div>
</div>
</template>
<script>
import header from "@/components/header.vue"
export default {
name: 'App',
data(){
return { }
},
components:{
'v-header':header
}
}
</script>
<style>
</style>
hell.vue
<template>
<div class="hell">
<div class="tabs">
<router-link to="/hell/product" class="tab-item">商品</router-link>
<router-link to="/hell/pinlun" class="tab-item">评论</router-link>
<router-link to="/hell/seller" class="tab-item">商家</router-link>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default{
data() {
return{
seller:{}
}
}
}
</script>
<style>
#app .tabs{
display: flex;
width: 100%;
height:40px;
line-height: 40px;
border-bottom:1px solid #cccccc;
}
#app .tabs .tab-item{
flex: 1;
text-align: center;
}
.router-link-active{
color: orange;
}
</style>
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import hell from '@/components/hell'
import header from '@/components/header'
import product from '@/components/product'
import pinlun from '@/components/pinlun'
import seller from '@/components/seller'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: hell,
},{
path: '/hell',
component: hell,
children:[
{
path: '/',component: hell
},
{
path: 'product',component: product
},
{
path: 'pinlun',component: pinlun
},
{
path: 'seller',component: seller
}
]
}
]
})
header.vue
header.png
弹框.png
<template>
<div class="header">
<div class="headercontent">
<div class="avatar">
<img :src="seller.avatar" alt="" width="64" height="64">
</div>
<div class="content">
<div class="title">
<div class="con-pic"></div>
<h1 class="name">{{seller.name}}</h1>
</div>
<h2 class=time>{{seller.description}}/{{seller.deliveryTime}}分钟送达
</h2>
<div class="support" v-if="seller.supports">
<span class="icon1" :class="classmap[seller.supports[0].type]"></span>
<span class="text1">{{seller.supports[0].description}}</span>
</div>
<!-- 不加v-if="seller.supports"会报错
原因是:一开始就会把seller传递给header组件,但是我们获取数据是异步请求,
一开始初始化seller的时候是个空对象,把空对象传递给header的时候,
这个seller.supports就是undefined,所以获取seller.supports[0]就会报错
-->
</div>
<div class="supportcount" v-if="seller.supports" @click="sellermodel">
<span class="count">{{seller.supports.length}}个</span>
<i class="icon-keyboard_arrow_right"></i>
</div>
</div>
<div class="headerbulletin" @click="sellermodel">
<span class="bulletin-title"></span>
<span class="bulletin-text">{{seller.bulletin}}</span>
<i class="icon-keyboard_arrow_right icon-right"></i>
</div>
<div class="headerbg">
<img :src="seller.avatar" alt="" width="100%" height="100%">
</div>
<transition name="fade">
<div class="sellermodel" v-show="modelshow">
<div class="model-wrapper clearfix">
<div class="model-main">
<h1 class="name">{{seller.name}}</h1>
<div class="star-wrapper">
<star :size="48" :score="seller.score"></star>
</div>
<div class="modeltitle">
<div class="line"></div>
<div class="text">优惠信息</div>
<div class="line"></div>
</div>
<div class="supports" v-if="seller.supports">
<ul>
<li v-for="(item,index) in seller.supports" class="supports-item">
<span :class="classmap[seller.supports[index].type]" class="icon2"></span>
<h1 class="text-title">{{seller.supports[index].description}}</h1>
</li>
</ul>
</div>
<div class="modeltitle">
<div class="line"></div>
<div class="text">商家公告</div>
<div class="line"></div>
</div>
<div class="bulletin">
<p class="con-content">{{seller.bulletin}}</p>
</div>
</div>
</div>
<div class="model-close" @click="modelclose">
<i class="icon-close"></i>
</div>
</div>
</transition>
</div>
</template>
<script>
import axios from 'axios';
import star from "@/components/star"
export default {
name: 'App',
data(){
return {
seller:[],
modelshow:false,
}
},
components:{star},
methods:{
sellermodel(){
this.modelshow = true
},
modelclose(){
this.modelshow = false
}
},
created:function(){
axios.get('../static/data.json').then((response) =>{
this.seller = response.data.seller;
console.log(this.seller);//获取数据
}).catch((error) =>{
})
this.classmap=['decrease','discount','special','invoice','guarantee'];
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
body,html{font-weight: 200;font-size: 0;}
.header{background-color: rgba(7,17,27,0.5);position: relative;overflow: hidden;}
.headercontent{
color:#ffffff;
padding:24px 12px 18px 24px;
font-size: 0;
}
.avatar{
display: inline-block;
margin-right: 16px;
width: 64px;
overflow: hidden;
vertical-align: top;
border-radius: 2px;
}
.content{display: inline-block;font-size: 14px;vertical-align: middle;width: 4.4rem;}
.title{margin:2px 0 2px 0;font-size: 0;}
.con-pic{
width: 30px;
height: 18px;
display: inline-block;
margin-right: 6px;
background-size: 30px 18px;
background-image: url(../assets/img/brand@2x.png);
vertical-align: top;
}
.name{display: inline-block;font-size: 16px;color: #ffffff;font-weight: bold;line-height: 18px; }
.time{font-size: 12px;line-height: 24px;color: rgba(255,255,255,0.9);}
.icon1{
display: inline-block;
vertical-align: middle;
width: 12px;
height:12px;
margin-right:4px;
background-size: 12px 12px;
background-repeat: no-repeat;
}
.decrease{
background-image: url(../assets/img/decrease_1@2x.png);
}
.discount{
background-image: url(../assets/img/discount_1@2x.png);
}
.special{
background-image: url(../assets/img/special_1@2x.png);
}
.invoice{
background-image: url(../assets/img/invoice_1@2x.png);
}
.guarantee{
background-image: url(../assets/img/guarantee_1@2x.png);
}
.text1{font-size: 0.2rem;color: #ffffff;line-height: 0.24rem;display: inline-block;}
.supportcount{
display: inline-block;
vertical-align:middle;
color:#ffffff;
line-height: 0.24rem;
background-color: rgba(0,0,0,0.2);
height:0.48rem;
border-radius: 0.24rem;
line-height: 0.48rem;
padding:0 8px;
text-align: center;
}
.count{font-size: 0.2rem;}
.icon-keyboard_arrow_right{
font-size: 0.2rem;
color: #ffffff;
}
.headerbulletin{
height: 0.56rem;
background-color: rgba(7,17,27,0.2);
padding: 0 0.24rem ;
font-size: 0;
}
.bulletin-title{
width: 0.44rem;
height: 0.24rem;
display: inline-block;
margin-right: 4px;
background-size: cover;
background-image: url(../assets/img/bulletin@2x.png);
vertical-align: middle;
margin-bottom:1px;
}
.bulletin-text{
width: 6.25rem;
height: 0.56rem;
line-height: 0.56rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
display: inline-block;
font-size: 0.2rem;
color: rgba(255,255,255,0.9);
vertical-align: middle;
}
.icon-right{vertical-align: middle;display: inline-block;font-size: 0.24rem;}
.headerbg{
position: absolute;
left:0; top:0;
width: 100%;
height:100%;
z-index: -1;
filter: blur(10px);
}
.sellermodel{
position: fixed;
top:0;
left:0;
width: 100%;
height:100%;
background:rgba(7,17,27,0.8);
z-index: 100;
overflow: auto;
transition: all 0.5s;
backdrop-filter:blur(10px);
}
.sellermodel .fade-transition{opacity: 1;background: rgba(7,17,27,0.8);}
.fade-enter,.fade-leave{opacity: 0;background: rgba(7,17,27,0);}
.model-wrapper{min-height: 100%;font-size: 0;width: 100%; }
.model-main{
margin-top:64px;
padding-bottom: 64px;
color: #ffffff;
}
.star-wrapper{margin:0 auto;margin-top:18px;padding:2px 0;text-align: center;}
.modeltitle{display: flex;width: 80%;margin:30px auto 24px auto;}
.line{flex: 1;position: relative;top:-6px;border-bottom: 1px solid rgba(255,255,255,0.2)}
.text{padding:0 12px;font-size: 0.28rem;}
.model-close{
position: relative;
width:32px;
height:32px;
margin:-64px auto 0 auto;
clear: both;
text-align: center;
}
.icon-close{font-size: 32px;color: rgba(255,255,255,0.5);}
.model-main .name{font-size: 0.32rem;color: #ffffff;line-height: 0.32rem;text-align: center;width: 100%;}
.supports{width: 80%;margin:0 auto;}
.supports-item{padding:0 0.24rem;margin-bottom: 0.24rem;font-size: 0;}
.supports-item:last-child{margin-bottom: 0;}
.icon2{
display: inline-block;
width: 16px;
height:16px;
vertical-align: top;
margin-right:6px;
background-size: 16px 16px;
background-repeat: no-repeat;
}
.text-title{font-size: 0.24rem;line-height: 16px;display: inline-block;}
.bulletin{width: 80%;margin:0 auto;}
.con-content{font-size: 0.24rem;font-weight: 200;color: #ffffff;line-height: 0.48rem;padding:0 0.24rem ;}
</style>
star.vue(星星组件) 此乃子组件,根据父组件传参来改变
<template>
<div class="star" :class="startype">
<span v-for="staritem in staritems" :class="staritem" class="item-star"></span>
</div>
</template>
<script type="text/javascript">
const LENGTH = 5;
const CLS_ON = 'on';
const CLS_HALF = 'half';
const CLS_OFF = 'off';
export default {
data(){
return {}
},
props:{
size:{
type:Number
// 接收24,36,48(图片尺寸)
},
score:{
type:Number
}
},
computed:{
startype(){
return 'star-'+this.size;
},
staritems(){
let result = [];
let score = Math.floor(this.score*2)/2;//小数点一位
let hasDecimal = score % 1 !==0;//是否有小数
let integer = Math.floor(score);
for(let i=0;i<integer;i++){
result.push(CLS_ON);//全星
}
if(hasDecimal){
result.push(CLS_HALF);//半星
}
while(result.length<LENGTH){
result.push(CLS_OFF);//没有星
}
return result;
}
}
};
</script>
<style scoped>
.star{font-size: 0;}
.item-star{display: inline-block;background-repeat: no-repeat;}
.star-48 .item-star{width: 20px;height: 20px;margin-right:22px;background-size: 20px 20px;}
.star-48 .on{background-image: url('../assets/img/star48_on@2x.png');}
.star-48 .half{background-image: url('../assets/img/star48_half@2x.png');}
.star-48 .off{background-image: url('../assets/img/star48_off@2x.png');}
.star-36 .item-star{width: 15px;height:15px;margin-right: 6px;background-size: 15px 15px;}
.star-36 .on{background-image: url('../assets/img/star36_on@2x.png');}
.star-36 .half{background-image: url('../assets/img/star36_half@2x.png');}
.star-36 .off{background-image: url('../assets/img/star36_off@2x.png');}
.star-24 .item-star{width: 10px;height:10px;margin-right: 3px;background-size: 10px 10px;}
.star-24 .on{background-image: url('../assets/img/star24_on@2x.png');}
.star-24 .half{background-image: url('../assets/img/star24_half@2x.png');}
.star-24 .off{background-image: url('../assets/img/star24_off@2x.png');}
.star .item-star:last-child{margin-right: 0;}
</style>
网友评论