❤ 项目源码 ❤
GitHub地址:https://github.com/Umbrella001/mtapp
格式:<当前城市定位>美团 > <当前城市定位><所在城市地区名>
HTML:使用E-UI的面包屑页面代码
https://element.eleme.cn/#/zh-CN/component/breadcrumb
这种有静态属性的拼接,为了避免浏览器重绘闪动,使用ssr去服务端渲染;
<div class="m-crumbs">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">{{ $store.state.geo.position.city.replace('市','') }}美团el-breadcrumb-item>
<el-breadcrumb-item><a href="/">{{ $store.state.geo.position.city.replace('市','') }}{{ decodeURIComponent(keyword) }}a>el-breadcrumb-item>
el-breadcrumb>
div>
catagroy.vue:
总列表通过上下两部分去循环,此时是不带弹出层的,这个当成组件开发iselect.vue
<dl class="classic">
<dt>分类dt>
<dt>全部dt>
<dd
v-for="(item,idx) in types"
:key="idx">
<iselect
:name="item.type"
:list="item.module"/>
dd>
dl>
<dl class="classic">
<dt>区域dt>
<dt>全部dt>
<dd
v-for="(item,idx) in areas"
:key="idx">
<iselect
:name="item.type"
:list="item.module"/>
dd>
dl>
iselect.vue :
注意接收的数据是hover时对应的数据头,在请求
<template>
<div class="m-product-select">
<dl class="tab">
<dt>{{ name }}<i class="el-icon-arrow-down el-icon--right"/>dt>
<dd>
<h3>{{ name }}h3>
<span
v-for="(item,idx) in list"
:key="idx">{{ item }}span>
dd>
dl>
div>
template>
// javascript
export default {
props: {
name: {
type:String,
default:''
},
list: {
type: Array,
default(){
return []
}
}
}
}
先循环每一个产品整体卡 list.vue > Item
<div class="m-products-list">
<dl>
<dd
v-for="item in nav"
:key="item.name"
:class="[item.name,item.active?'s-nav-active':'']"
@click="navSelect"
>{{ item.txt }}dd>
dl>
<ul>
<Item
v-for="(item,idx) in list"
:key="idx"
:meta="item"/>
ul>
div>
产品卡内部DOM结构 product.vue
》评分Rate使用E-UI的评分系统
<template>
<dl class="s-item">
<dt>
<img
:src="meta.img"
alt="商品图片">
dt>
<dd>
<h3><nuxt-link :to="{path:'detail',query:{keyword:meta.name,type:meta.module}}">{{ meta.name }}nuxt-link>h3>
<el-rate
v-model="meta.rate"
:colors="['#ff9900', '#ff9900', '#FF9900']"
disabled/>
<span
v-if="meta.rate>4"
class="s-item-comment">很好span><span
v-else-if="meta.rate>3"
class="s-item-comment">一般span><span
v-else
class="s-item-comment">很差span>
<span class="s-item-value">{{ meta.rate }}分span>
<span class="s-item-comment-total">{{ meta.comment }}人评论span>
<p>
<span class="s-item-type">{{ meta.type }}span>
<span class="s-item-addr">{{ meta.addr }}span>
p>
<p>
<em class="s-item-price">¥{{ meta.price }}起em>
<b>{{ meta.status }}b>
p>
<ul>
<li v-if="meta.scene&&meta.scene.length">
<span class="detail-type">景酒span>{{ meta.scene }}
li>
<li v-else>
<span class="detail-type">景酒span>暂无描述
li>
ul>
dd>
dl>
template>
<script>
export default {
props: {
meta: {
type:Object,
default(){
return {}
}
}
}
}
script>
注意:
注意这里中使用的数据结构就是是对象,但之前不是说循环必须使用数组Array吗?但是这里注意,我们在 list.vue
的确是循环list就是数组,但是它里面的数据,是分成另一个组件去开发,所以这里传过去的,当然可以是对象,也务必是对象,为什么? 因为前后端数据格式都不一样,前端要有自己的对象数据,这样即使后端偷偷该数据,我们也只是改个拿数据的地方,而并不需要改动HTML的地方,明白我意思没,前端要漫步映射后端的字段
百度搜索高德地图开放平台 https://lbs.amap.com/ → 成功注册后
→ 点击产品介绍下的地图
→ 移动到页面底部选择【javascript API】
→ 点击控制台,进入【应用管理】,获取key值
→ 找到javascript的【地图控件】参考文档做即可(注意这里引入地图控件js的话在【准备】,用框架的话就使用异步导入的方式),最终的代码差不多为这样:
<template>
<div
:id="id"
:style="{width:width+'px',height:height+'px',margin:'34px auto'}"
class="m-map"/>
</template>
<script>
export default {
props: {
width: {
type:Number,
default:300
},
height: {
type:Number,
default:300
},
point: {
type:Array,
default(){
return [116.46,39.92]
}
}
},
data() {
return {
id: `map`,
key: '2fc3f4c37d30bd0b4cdecb85ed8c249f'
}
},
watch: {
point: function (val, old) {
this.map.setCenter(val)
this.marker.setPosition(val)
}
},
mounted() {
let self = this
self.id = `map${Math.random().toString().slice(4, 6)}`
window.onmaploaded = () => {
let map = new window.AMap.Map(self.id, {
resizeEnable: true,
zoom: 11,
center: self.point
})
self.map = map
window.AMap.plugin('AMap.ToolBar', () => {
let toolbar = new window.AMap.ToolBar()
map.addControl(toolbar)
let marker = new window.AMap.Marker({
icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
position: self.point
})
self.marker = marker
marker.setMap(map)
})
}
const url = `https://webapi.amap.com/maps?v=1.4.10&key=${self.key}&callback=onmaploaded`
let jsapi = document.createElement('script')
jsapi.charset = 'utf-8'
jsapi.src = url
document.head.appendChild(jsapi)
},
}
</script>
关于地图相关控件,差不多按照上面的格式配合文档写就行
1.既然图片提出来做单独组件的话,那就不要定死数据,比如地图DOM节点的宽高和id名就应该使用动态数据
<template>
<el-row class="page-product">
<el-col :span="19">
<crumbs :keyword="keyword"/>
<categroy
:types="types"
:areas="areas"/>
<list :list="list"/>
el-col>
<el-col :span="5">
<amap
v-if="point.length"
:width="230"
:height="290"
:point="point"/>
el-col>
el-row>
template>
<script>
import Crumbs from '@/components/products/crumbs.vue'
import Categroy from '@/components/products/categroy.vue'
import List from '@/components/products/list.vue'
import Amap from '@/components/public/map.vue'
export default {
components:{
Crumbs,
Categroy,
List,
Amap
},
data(){
return {
list:[],
types:[],
areas:[],
keyword:'',
point:[]
}
},
async asyncData(ctx){
let keyword = ctx.query.keyword
let city = ctx.store.state.geo.position.city
let {status,data:{count,pois}} = await ctx.$axios.get('/search/resultsByKeywords',{
params:{
keyword,
city
}
})
let {status:status2,data:{areas,types}} = await ctx.$axios.get('/categroy/crumbs',{
params:{
city
}
})
if(status===200&&count>0&&status2===200){
return {
list: pois.filter(item=>item.photos.length).map(item=>{
return {
type: item.type,
img: item.photos[0].url,
name: item.name,
comment: Math.floor(Math.random()*10000),
rate: Number(item.biz_ext.rating),
price: Number(item.biz_ext.cost),
scene: item.tag,
tel: item.tel,
status: '可订明日',
location: item.location,
module: item.type.split(';')[0]
}
}),
keyword,
areas: areas.filter(item=>item.type!=='').slice(0,5),
types: types.filter(item=>item.type!=='').slice(0,5),
point: (pois.find(item=>item.location).location||'').split(',')
}
}
}
}
script>
总结:
有没有发现入口文件,发了主要的请求(对比page文件夹下的changeCity.vue
和products.vue
),他们各自特点,前者是子组件中自己发送请求,自给自足,最后总入口文件 changeCity.vue
引入即可;后者则是入口组件发送请求,然后发放个对应的组件,也就是父传子的思想,而各自组件就接收 products.vue
传递过来的数据
❤ 项目源码 ❤
GitHub地址:https://github.com/Umbrella001/mtapp