【Vue】《从0开始写一个WebApp》其四

其四:附近店铺和商家详情

post、get请求封装

前后端通信时,一般会根据接口选择post或get请求。前面使用模拟接口实现登陆时,只封装了post方法。在进行接下来的开发时,先把get方法也封装一下。

在src/utils/request.js下。将post部分的代码复制一份,改成get请求。将data改为params,去掉headers的参数。

export const get = (url, params = {}) => {
	return new Promise((resolve, reject) => {
		axios.get(url, { params },{
			baseURL:...
		}).then(
			(res) => {
				resolve(res)
			},
			(err) => {
				reject(err)
			}
		)
	})
}

再改进一下,将post和get中相同的部分抽离出来

const instance = axios.create({
	baseURL:
		"...",
	timeout: 10000,
})

将两个请求的axios换成instance,并去掉第三个参数的配置。

之后,其他组件需要发送post/get请求,只需要导入这个函数。

附近店铺数据动态化

前面介绍过将数据存在List中,用v-for循环。这里可以把List的数据动态化,即数据从请求接口来。

因为根据实际需求,附近店铺应该是与使用者的位置有关的,不同位置会显示不同的店铺。在进入首页后,应该先获取一下定位信息,然后将定位信息发给后端,再向后端请求数据,这时后端会返回对应位置的附近店铺的数据。这样才能在页面展示正确的店铺信息。

首先在fastmock上新建一个接口,get请求。数据返回的格式根据List一致。比如

dockerList:[
	{
		icon:"",
		title:"首页"
	},
	{
		icon:"",
		title:"购物车"
	}
]
//接口返回的数据:
{
	"error":0,
	"data":[
		{
		icon:"",
		title:"首页"
	},
	{
		icon:"",
		title:"购物车"
	}
	]
}

(因为我是用自己的接口,所以数据格式可以自己定。为了方便我就设置成一样的了。实际开发中,应根据实际接口返回的数据调整你的html结构。)

然后调用下之前封装的get请求。

		getNearByInfo() {
			get("/nearby-list").then(this.getNearByInfoSucc)
		},
		getNearByInfoSucc(res) {
			const data = res.data
			if (data.error != 0) return
			this.items = data.data
		},

在页面加载完成时调用下getNearByInfo

商家详情页开发

组件复用和样式定制

根据设计图发现有很多可以复用的地方。比如NearBy那个展示店铺的框。

将那块代码抽离出来封装成ShopInfo组件,当然一下class的名称可以改。

Nearby页面引入这个组件,将item传入。

<shop-info v-for="item in items" :key="item.item_id" :item="item" />

Shop页面也可以使用这个组件,但是根据设计图,Shop页面是没有border-bottom的,这时候可以再传入一个参数:hideBorder,并将ShopInfo中关于border-bottom的样式拆出来放另一个类里。通过判断hideBorder的值来决定border-bottom显示不显示。

跳转至商家详情

设置对应路由/shop,再给shop-info设置跳转链接

{
		path: "/shop",
		name: "Shop",
		component: () =>
			import(/* webpackChunkName: "shop" */ "../views/Shop.vue"),
	}
<router-link
			to="/shop"
			v-for="item in items"
			:key="item.item_id"
		>
			<shop-info :item="item" />
</router-link>

获取对应的商家详情

从不同店铺点击,进入的商家详情页面应该是不一样的。给/shop路由加一个参数,跳转时需要传入这参数才能显示页面。

同样,shop-info的跳转链接也要有变化

path: "/shop/:id",
router-link:
	:to="`/shop/${item.item_id}`"

这样点击附近店铺下的店铺,跳转至shop页面的时候,url会加上/id。

接下来,要在shop页面获取对应的数据。

先写一个示范接口,在fastmock里创建一个新的接口,get请求,路径为/shop/:id。请求成功的内容如下“

{
  "error":0,
  "data":[{
					item_id: 1,
					item_img: {
						src: "http://www.dell-lee.com/imgs/vue3/near.png",
						alt: "沃尔玛",
					},
					item_info: {
						title: "沃尔玛",
						desc: ["月售1万+", "起送¥0", "基础运费¥5"],
					},
					item_heighlight: "VIP尊享满89元减4元运费券(每月3张)",
				}]
}

Shop页面也使用了shop-info这个组件,

<shop-info :item="item" :hideBorder="true" />

定义请求接口,获取的值赋值给data里的item,并在mounted周期里调用。

getShopInfo() {
			get("/shop/1").then(this.getShopInfoSucc)
		},
		getShopInfoSucc(res) {
			if (res.data.error !== 0) return
			const data = res.data
			this.item = data.data[0]
		},

这样页面能渲染出来,但是会报一个警告。是因为mounted周期组件已经渲染完成,但是data里的item还是空的。可以加一个v-if判断

<shop-info v-if="item.item_id" :item="item" :hideBorder="true" />

等item有值了再渲染这个组件。

接下来,请求的地址应该根据url里id的值变化。

使用this.$route获取url里的id

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QuQ1VeEP-1616756714912)(D:\Information\typoraMD\京东\images\route.png)]

get("/shop/1")=>
get(`/shop/${this.$route.params.id}`)

布局

在这里插入图片描述

组件

大概就是布局分的那样,有三部分

search__bar

样式没啥好说的,按钮绑定事件,通过this.$route.back()返回上一页。

shop-info

直接复用的代码,item的值由该页面传入。

shop-content

分为左侧的catalog和右侧的shop。

期望实现的功能是,点击左侧,对应样式改变,右侧的商品也改变。

可以在点击左侧的列表时,向后端发出一个请求,这个请求包含一个参数tab。tab为all的时候,返回全部商品的数据,tab为kill的时候,返回秒杀的数据。右侧的商品根据左侧获得的数据渲染。

在fastmock上新建一个接口,get请求,发送地址为/shop/:id/products。内部结构为

{
  "error": 0,
  "data": [
    {
      "_id": "1",
      "name": "番茄 250g / 份",
      "imgUrl": "http://www.dell-lee.com/imgs/vue3/tomato.png",
      "sales": 10,
      "price": 33.6,
      "oldPrice": 39.6
    },
	{.....}
  ],
  "message": "errno !== 0 时的错误信息"
}

在左侧标签绑定点击事件

getProdctInfo(tab) {
			get("/shop/:id/products", { tab }).then(this.getProdctInfoSucc)
		}
<li ...
	@click="() => {
					getProdctInfo(item.tab)
					}"
></li>

这样,点击不同的标签会发送带不同参数值的请求。

在这里插入图片描述

如何让左侧的样式也一起改变呢?为了方便,左侧列表由一个数组渲染,数组的结构如下:

catalog_list: [
				{
					name: "全部商品",
					tab: "all",
				},
				{
					name: "秒杀",
					tab: "kill",
				},
				{
					name: "新鲜水果",
					tab: "fruit",
				},
			],

首次进入页面时,应当展现第一个标签下的商品。即

dataTab = catalog_list[0].tab

直接在data里赋值是不行的,在mounted周期里赋值,并用这个值获取一次商品数据。

mounted() {
		this.dataTab = this.catalog_list[0].tab
		this.getProdctInfo(this.dataTab)
	}

之后每次点击左侧的列表项时,也应该重新对dataTab赋值

getProdctInfo(tab) {
			this.dataTab = tab
			get("/shop/:id/products", { tab }).then(this.getProdctInfoSucc)
		}

也就是说,当dataTab === item.tab的时候,这个item是被选中的,可以添加选中样式。那么li标签的样式可以更换成这样

:class="{catalog__item: true,'catalog__item--active': dataTab === item.tab,}"

路由加载优化

用这种方式加载

{
		path: "/",
		name: "Home",
		component: () =>
		import(/* webpackChunkName: "home" */ "../views/Home.vue"),
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值