每个步骤都有对应的一份代码和截图,按部就班。
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm install vue-cli -g
vue init webpack meituanwaimai
cd meituan
cnpm install
cnpm run dev
http://localhost:8080
<template> <ul class="tab-bar"> <li ><i class="icon-index"></i><span>首页</span></li> <li ><i class="icon-order"></i><span>订单</span></li> <li ><i class="icon-mine"></i><span>个人</span></li> </ul> </template> <script> export default { components: {}, data () { return {} }, props: {}, watch: {}, methods: {}, filters: {}, computed: {}, created () {}, mounted () {}, destroyed () {} } </script> <style scoped> .tab-bar { position: fixed; bottom: 0; width: 100%; height: 49px; text-align: center; border-top: 1px solid rgb(182, 182, 182); background-color: #fcfcfc; display: flex; flex-direction: row; } li { flex: 1; color: #999; } i { display: block; width: 25px; height: 25px; margin: 3px auto; background: url('./tabbarBg.png') no-repeat; background-size: 25px auto; } span { display: block; font-size: 12px; } .icon-index { background-position: 0 -75px; } .icon-order { background-position: 0 -25px; } .icon-mine { background-position: 0 -125px; } </style>
cnpm install vue-router --save
css
本例的vue-router就是一个vue-router最简单的用法,把每一个组件对应路径就行了。而后在main.js中引入它,而后绑定在vue实例中就能够了。
import Vue from 'vue' import Router from 'vue-router' import Index from '@/components/index/index' import Order from '@/components/order/order' import Mine from '@/components/mine/mine' Vue.use(Router) export default new Router({ routes: [ // 根路径 { path: '/', redirect: '/index' }, // 首页 { path: '/index', component: Index }, // 订单 { path: '/order', component: Order }, // 个人 { path: '/mine', component: Mine } ] })
选中样式会默认加上router-link-active样式,只要在这个样式中把选中图片替换掉就好(这里是改变图片位置)。把li替换成router-link,tag表示对应的标签,to表示点击它会router-view会显示的组件html
<template> <ul class="tab-bar"> <router-link tag="li" to="/index"><i class="icon-index"></i><span>首页</span></router-link> <router-link tag="li" to="/order"><i class="icon-order"></i><span>订单</span></router-link> <router-link tag="li" to="/mine"><i class="icon-mine"></i><span>个人</span></router-link> </ul> </template> <script> export default { components: {}, data () { return {} }, props: {}, watch: {}, methods: {}, filters: {}, computed: {}, created () {}, mounted () {}, destroyed () {} } </script> <style scoped> .tab-bar { position: fixed; bottom: 0; width: 100%; height: 49px; text-align: center; border-top: 1px solid rgb(182, 182, 182); background-color: #fcfcfc; display: flex; flex-direction: row; } li { flex: 1; color: #999; } i { display: block; width: 25px; height: 25px; margin: 3px auto; background: url('./tabbarBg.png') no-repeat; background-size: 25px auto; } span { display: block; font-size: 12px; } .icon-index { background-position: 0 -75px; } .icon-order { background-position: 0 -25px; } .icon-mine { background-position: 0 -125px; } .router-link-active { color: #333; } .router-link-active .icon-index { background-position: 0 -50px; } .router-link-active .icon-order { background-position: 0 0px; } .router-link-active .icon-mine { background-position: 0 -100px; } </style>
在reset.css中把html、body高度设置为100%,把app组件的高度也设置为100%就能全屏高度
cnpm install mint-ui --save
vue
import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' Vue.use(MintUI)
<div class="slider"> <mt-swipe :auto="3000"> <mt-swipe-item v-for="item in swipeData" :key="item.pic"> <img :src="item.pic"> </mt-swipe-item> </mt-swipe> </div> data () { return { swipeData: [ {pic: require('./img/swipe/1.jpg')}, {pic: require('./img/swipe/2.jpg')} ], } } .slider { height: 170px; font-size: 30px; text-align: center; overflow: hidden; } .slider img { width: 100%; }
data () { return { swipeData: [ { pic: require('./img/swipe/1.png') }, // { // pic: require('./img/swipe/1.png') // } ], types:[ { icon: require('./img/types/ms.png'), title: '美食' }, { icon: require('./img/types/mtcs.png'), title: '美团超市' }, { icon: require('./img/types/sxgs.png'), title: '生鲜果蔬' }, { icon: require('./img/types/tdyp.png'), title: '甜点饮品' }, { icon: require('./img/types/mtzs.png'), title: '美团专送' }, { icon: require('./img/types/zcyx.png'), title: '正餐优选' }, { icon: require('./img/types/kcxc.png'), title: '快餐小吃' }, { icon: require('./img/types/hbps.png'), title: '汉堡披萨' } ] } }
<template> <div class="types-item"> <img src="../../index/img/types/hbps.png" > <span>汉堡披萨</span> </div> </template> <style scoped> .types-item { float: left; width: 25%; padding-top: 14px; } .types-item img { display: block; width: 50px; margin: 0 auto 12px; } .types-item span { display: block; font-size: 14px; line-height: 14px; text-align: center; color: #2f2f2f; } </style>
<!-- 种类 --> <div class="types"> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> <types-item ></types-item> </div> import typesItem from '@/components/base/types-item/types-item'
引入.vue文件时使用的@是在webpack.base.conf.js文件的alias位置配置的,在须要写路径时均可以在这里配置绝对路劲的简写方式
index.vue <div class="types"> <types-item v-for="item in types" :icon="item.icon" :title="item.title" :key="item.title"></types-item> </div> types-item.vue <template> <div class="types-item"> <img :src="icon" > <span v-text="title"></span> </div> </template> props: { icon:{ type:String, default:'' }, title:{ type:String, default:'' } },
这里数据仅仅为3条,项目中复制了4分共12条数据,列表中须要须要对数据判断的几个地方:node
shopList: [ { "id": 1000,//id "type":1,//1表明新店、2表明品牌店、0表明都不是 "name": "你的名字",//店名 "delivery_type": 1,//1表明美团专送,0表明不是 "pic_url": "http://p0.meituan.net/0.84.63/xianfu/54c60749841a6612df373dc259e8da73108176.jpg",//图片地址 "avg_delivery_time": 30,//平均送达时间 "delivery_distance": 2032,//平均送达距离(单位为米,超过一公里要转化成公里) "min_price": 20,//起送价 "delivery_price": 3,//配送费 "wm_poi_score": 4.7,//评分 "month_sale_num": 33,//月售 "shop_discount": { "code":0,//是否能领代金券 "dis_money":[2,4]//返回的代金券(多张) }, "shop_return_price": { "code":0,//是否返券 "min_price":20,//返券起始价格 "dis_money":4//商家返券数 }, "shop_return_invoice": { "code":0,//是否开发票 "min_price":0,//开票起始价格 }, }, { "id": 1001,//id "type":0,//1表明新店、2表明品牌店、0表明都不是 "name": "叫了个炸鸡(鼓楼店)",//店名 "delivery_type": 1,//1表明美团专送,0表明不是 "pic_url": "http://p0.meituan.net/0.84.63/xianfu/00b9386a556a39010186a609ce9289e370566.jpg",//图片地址 "avg_delivery_time": 30,//平均送达时间 "delivery_distance": 2502,//平均送达距离(单位为米,超过一公里要转化成公里) "min_price": 20,//起送价 "delivery_price": 3,//配送费 "wm_poi_score": 4.2,//评分 "month_sale_num": 3857,//月售 "shop_discount": { "code":1,//是否能领代金券 "dis_money":[1,5,10]//返回的代金券(多张) }, "shop_return_price": { "code":0,//是否返券 "min_price":20,//返券起始价格 "dis_money":1//商家返券数 }, "shop_return_invoice": { "code":0,//是否开发票 "min_price":0,//开票起始价格 }, }, { "id": 1002,//id "type":2,//1表明新店、2表明品牌店、0表明都不是 "name": "望湘园(南京国际广场店)",//店名 "delivery_type": 0,//1表明美团专送,0表明不是 "pic_url": "http://p1.meituan.net/0.84.63/xianfu/2d91e93c70f91696907f040392c4835f13918.jpg",//图片地址 "avg_delivery_time": 30,//平均送达时间 "delivery_distance": 889,//平均送达距离(单位为米,超过一公里要转化成公里) "min_price": 20,//起送价 "delivery_price": 3.5,//配送费 "wm_poi_score": 4.7,//评分 "month_sale_num": 1435,//月售 "shop_discount": { "code":0,//是否能领代金券 "dis_money":[2,4]//返回的代金券(多张) }, "shop_return_price": { "code":0,//是否返券 "min_price":20,//返券起始价格 "dis_money":4//商家返券数 }, "shop_return_invoice": { "code":1,//是否开发票 "min_price":0,//开票起始价格 }, } ]
index.vue <!-- 周边商铺 --> <div class="nearby"> <shop-list-item v-for="item in shopList" :item= "item"></shop-list-item> </div> shop-list-item.vue <div class="seller-list-item" > <div class="left"> <span :class="{pingpai:item.type===2,xindian:item.type===1,hide:item.type===0}">{{item.type===1?"新店":"品牌"}}</span> <img :src="item.pic_url"> </div> </div>
<div class="seller-list-item" > <div class="left"> <span :class="{pingpai:item.type===2,xindian:item.type===1,hide:item.type===0}">{{item.type===1?"新店":"品牌"}}</span> <img :src="item.pic_url"> </div> <div class="content"> <div class="name">{{item.name}}</div> <div class="mid"> <span class="fl">* * * * *</span> <span class="count fl">月售{{ item.month_sale_num }}</span> <span class="distance fr">{{ distance }}</span> <span class="time fr">{{ item.avg_delivery_time }}分钟 |</span> </div> <div class="down"> <span >起送 {{ item.min_price }} |</span> <span >配送 {{ item.delivery_price }} |</span> <!-- 数据中忘了平均消费价格,这里直接用起送价格数据代替 --> <span >人均 {{ item.min_price + 6 }}</span> <div class="zhuansong" v-show="item.delivery_type === 1"> <span >美团专送</span> </div> </div> <ul class="activety"> <li class="jian" v-show="item.shop_discount.code"><img src="./jian.png" ><span>{{replacePrice}}</span></li> <li class="fan" v-show="item.shop_return_price.code"><img src="./fan.png" ><span>{{"实际支付" + item.shop_return_price.min_price + "元返" + item.shop_return_price.dis_money +"元商家代金券"}}</span></li> <li class="fapiao" v-show="item.shop_return_invoice.code"><img src="./piao.png" ><span>{{"本店支持开发票,开票金额" + item.shop_return_invoice.min_price + "元起"}}</span></li> </ul> </div> </div>
methods: { findMaxAndMin(arr) { var min = arr[0] var max = arr[0] for (var i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i] } if (arr[i] < min) { min = arr[i] } } return {max,min} } }, computed: { // 距离km、m换算 distance() { if (this.item.delivery_distance > 1000) { return (this.item.delivery_distance / 1000.0).toFixed(1) + 'km' }else { return this.item.delivery_distance + 'm' } }, // 代金券分一张和多张 replacePrice () { if (this.item.shop_discount.dis_money.length === 1) { return "可领" + this.item.shop_discount.dis_money[0] +"元代金券" }else { let {max,min} = this.findMaxAndMin(this.item.shop_discount.dis_money) return "可领" + min + "~" + max +"元代金券" } } },
.seller-list-item { margin-bottom: 5px; display: flex; flex-direction: row; padding: 12.5px 0 12.5px 0; overflow: hidden; margin-left:10px; border-bottom: solid 1px #eee; } /*左侧图片*/ .left { position: relative; flex: 0 0 86px; width: 86px; } .left span { display: inline-block; text-align: center; position: absolute; left: 0; top: 0; width: 28px; height: 14px; line-height: 14px; font-size: 12px; color: white; } span.hide { display: none; } span.pingpai { background-color: #ffa627; } span.xindian { background-color: #21c56c; } .left img { border:solid 1px #e4e4e4; display: block; width: 84px; height: 63px; margin: 0 auto; } /*右侧内容*/ .content { /*background-color: red;*/ flex: 1; display: flex; flex-direction: column; padding: 0 15px 0 10px; } .content .name { font-size: 17px; color: #333; overflow: hidden; font-weight: bold; overflow: hidden; } /*月售、送达时间、距离*/ .content .mid { flex: 1; margin-top: 7px; color: #666; font-size: 12px; } .mid .count { margin-left: 10px; } .mid .distance { margin-left: 5px; margin-top: 2px; } .mid .time { } /*起送配送人均*/ .down { flex: 1; margin-top: 7px; font-size: 13px; color: #656565; } .down .zhuansong { float: right; font-size: 13px; background-color: #ffd161; color: #333; } .zhuansong span { height: 15px; line-height: 15px; padding: 0 6px; display: inline-block; position: relative; } .zhuansong span::before, .zhuansong span::after { content: ''; position: absolute; border: 3px solid #fff; width: 0; height: 0; font-size: 0; } .zhuansong span::before { left: 0; top: 0; border-color: #fff #ffd161 #ffd161 #fff; } .zhuansong span::after { right: 0; bottom: 0; border-color: #ffd161 #fff #fff #ffd161; } /*活动*/ .activety { flex: 1; margin-top: 7px; color: #898989; font-size: 12px; text-align: left; } .activety li { height: 17px; margin-bottom: 4px; } .activety li img { width: 14px; height: 14px; vertical-align: middle; } .activety li span { vertical-align: middle; margin-left: 6px; }
把星星分为全星、半星、和无星星三种,好比3.7分就是3个全星星、1个半星星、一个无星星
<div> <i class="starItem" :class="{half:(score<1 && score> 0),zero:(score <= 0)}"></i> <i class="starItem" :class="{half:(score<2 && score> 1),zero:(score <= 1)}"></i> <i class="starItem" :class="{half:(score<3 && score> 2),zero:(score <= 2)}"></i> <i class="starItem" :class="{half:(score<4 && score> 3),zero:(score <= 3)}"></i> <i class="starItem" :class="{half:(score<5 && score> 4),zero:(score <= 4)}"></i> </div> .starItem { background: url(./star.png) no-repeat; background-size: cover; width: 10px; height: 10px; float: left; margin-right: 4px; background-position: 0 0; } .half { background-position: -14px 0; } .zero { background-position: -28px 0; }
新版vue-cli关闭了自动启动浏览器,能够经过吧build/config/index.js 中大概第18行的 autoOpenBrowser: false,改成true,而后从新启动npm run dev ,就能自动打开浏览器了
在webpack.dev.conf.js 中加入代码返回数据,webpack3内置了express,before方法的参数app就是express的实例对象
before(app) { var shops = require('../mock/shop.json') app.get('/api/shops', function(req, res) { res.json({ code: 0, data: shops }); }); }
安装axios,在main.js中引入axios
cnpm i axios --save
webpack
import axios from 'axios' Vue.prototype.axios = axios
在index.vue中获取数据
this.axios.get('/api/shops',{ params: { } }).then(res =>{ if (res.data.code === 0) { this.shopList = res.data.data } }).catch(error => { console.log(error) })