vue前台(五)
一,search组件的静态页面实现以及数据获取到vuex内
之前在home页,点击商品分类列表,跳转到search页,在search页我们需要获取数据,根据接口文档,需要一些请求参数,我们可从search组件的路由对象的query,params参数
获取需要的请求参数,然后在beforemounted中处理参数(此时已经初始化data参数了),然后在mounted中dispatch到vuex,将处理的请求参数传递过去。
1.1请求体参数searchParams需要初始化,重要
data() {
return {
//初始化搜索参数(收集搜索参数)
//为搜索请求提供搜索参数
searchParams: {
category1Id: "",
category2Id: "",
category3Id: "",
categoryName: "",
: "",
order: "1:desc",
pageNo: 1,
pageSize: 5,
props: [],
trademark: ""
}
};
},
1.2.在search组件中,对searchParams数据进行处理后,然后在发送ajax请求,此时需要在beforeMount()期间处理searchParams数据,因为在该组件期间,data的数据已经获取到了
methods: {
getGoodsListInfo() {
this.$store.dispatch("getGoodsListInfo", this.searchParams);
},
//处理searchParams参数
handlerSearchParams() {
//1、从路由中获取对应的params和query参数
let { keyword } = this.$route.params;
let {
categoryName,
category1Id,
category2Id,
category3Id
} = this.$route.query;
//2、拿到的这些参数都是可能有可能没有,需要判定,但是我们这次不判定直接全部放在一个新的对象当中
//...拆包对象,其实是浅拷贝
let searchParams = {
...this.searchParams,
keyword,
categoryName,
category1Id,
category2Id,
category3Id
};
//3、过滤这个对象当中没有数据的属性项
Object.keys(searchParams).forEach(item => {
if (!searchParams[item]) {
delete searchParams[item];
}
});
this.searchParams = searchParams;
},
beforeMount() {
//beforeMount 去同步更新data的searchParams数据
this.handlerSearchParams()
},
diapatch到vuex中,将请求参数传递过去
mounted() { this.getreqGoodList(); }, methods: { getreqGoodList() { this.$store.dispatch("getGoodsListInfo",this.searchParams)
}
1.3注;
此时通过home下的header组件(商品分类列表)路由到search页(/search),并且再次点击search页下的ypenav组件(search页的商品分类列表)路由到search组件(/search),(search路由路径没有变化,/search)前一次的路由组件生命周期还存在,没有销毁,所以query参数没有更新,只有切换路由组件(路由路径变化了),他才有生命周期,上一次生命周期没有销毁,下一次切换路由组件,就不会创建
1,当第一次切换路由组件,发送一次ajax请求,获取响应数据,当组件的params或query参数发生变化时,需要监视路由,需要再次处理searchParams,数据,再次发送一次ajax,获取新的响应数据, 我们需要监视search的路由对象,只要参数一变化,就会重新整理searchParams全情体数据,然后再次发送请求,
watch: {
$route() {
//还是要去准备参数再次发送请求,而这里的准备参数和beforMount内部是一模一样的
//因此我们可以把处理参数的过程封装一个公共的函数
this.handlerSearchParams()
//需要再次发送请求获取新的参数搜索的数据
this.getreqGoodsList();
}
},
2.在api文件中,封装ajax函数
引入import Ajax from '@/ajax/Ajax'
//请求search的商品搜索列表数据
// post /api/list data //data如果是空的对象代表没有搜索条件,会返回所有商品信息
// searchParams为请求体参数
export const reqGoodsList = (searchParams) => Ajax.post('/list',searchParams)
2.在store--创建search.js, 创建子vuex
注意;
import {reqGoodsList} from '@/api'
const state = {
goodsListInfo:{}
}
const mutations = {
//直接修改数据
RECEIVEGOODSLISTINFO(state,goodsListInfo){
state.goodsListInfo = goodsListInfo
}
}
const actions = {
//异步请求数据
//searchParams是用来接收组件dispatch传递过来的参数对象
//这个参数如果组件传递的就是一个数据,可以直接接收(什么数据类型都行)
//如果这个参数需要接收多个数据,必须封装成对象传递过来
async getGoodsListInfo({commit},searchParams){
const result = await reqGoodsList(searchParams)
if(result.code === 200){
commit('RECEIVEGOODSLISTINFO',result.data)
}
}
}
const getters = {
// 如果在组件中,获取数据,a.b.c,可能读取不到,报错“Error in render: "TypeError: Cannot read property '0' of undefined"
// 模板在渲染时,获取不到属性值,解决方式,在vuex中getters配置,获取不到时返回空数组,此时就不会报错
attrsList(state){
return state.goodsListInfo.attrsList || []
},
goodsList(state){
return state.goodsListInfo.goodsList || []
},
trademarkList(state){
return state.goodsListInfo.trademarkList || []
}
}
export default {
state,
mutations,
actions,
getters
}
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules:{
home,
search
}
})
4.在search组件中获取数据
computed: {
...mapGetters(["goodsList"])
},
二,search动态数据展示
1.将数据填充到模板中,商品数据
<div class="goods-list"> <ul class="yui3-g"> <li class="yui3-u-1-5" v-for="(goods, index) in goodsList" :key="goods.id"> <div class="list-wrap"> <div class="p-img"> <a href="item.html" target="_blank"> <img :src="goods.defaultImg" /> </a> </div> <div class="price"> <strong> <em>¥</em> <i>{{goods.price}}</i> </strong> </div> <div class="attr"> <a target="_blank" href="item.html" title="促销信息,下单即赠送三个月CIBN视频会员卡!【小米电视新品4A 58 火爆预约中】" >{{goods.title}}</a> </div> <div class="commit"> <i class="command"> 已有 <span>2000</span>人评价 </i> </div> <div class="operate"> <a href="success-cart.html" target="_blank" class="sui-btn btn-bordered btn-danger" >加入购物车</a> <a href="javascript:void(0);" class="sui-btn btn-bordered">收藏</a> </div> </div> </li> </ul> </div>
在search子组件中SearchSelector,获取vuex的数据
computed:{
...mapGetters(['attrsList','trademarkList'])
},
2.在html模板中填充数据,商品属性数据
<template> <div class="clearfix selector"> <div class="type-wrap logo"> <div class="fl key brand">品牌</div> <div class="value logos"> <ul class="logo-list"> <li v-for="(trademark, index) in trademarkList" :key="trademark.tmId" @click="$emit('searchForTrademark',trademark)">{{trademark.tmName}}</li> </ul> </div> <div class="ext"> <a href="javascript:void(0);" class="sui-btn">多选</a> <a href="javascript:void(0);">更多</a> </div> </div> <div class="type-wrap" v-for="(attr, index) in attrsList" :key="attr.attrId"> <div class="fl key">{{attr.attrName}}</div> <div class="fl value"> <ul class="type-list"> <li v-for="(attrValue, index) in attr.attrValueList" :key="index"> <a href="javascript:;" @click="$emit('searchForAttr',attr,attrValue)">{{attrValue}}</a> </li> </ul> </div> <div class="fl ext"></div> </div> </div> </template>
<li class="with-x" v-if="searchParams.categoryName"> {{searchParams.categoryName}} <i @click="removeCategoryName">×</i> </li> <li class="with-x" v-if="searchParams.keyword"> {{searchParams.keyword}} <i @click="removeKeyword">×</i> </li>
2.添加点击事件,删除面包屑,重新发送ajax请求搜索
2.1, 点击面包屑,让对应的参数为空,然后重新发送请求,获取数据
<ul class="fl sui-tag"> <li class="with-x" v-if="searchParams.categoryName">{{searchParams.categoryName}} <i @click="removeCategoryName">×</i> </li> <li class="with-x" v-if="searchParams.content">{{searchParams.content}} <i @click="removeContent">×</i> </li> </ul>
js代码
//删除列表名称的面包屑
removeCategoryName(){
this.searchParams.categoryName=''
// 出现发送请求
this.getGoodsListInfo();
},
//删除搜索框的名称的面包屑
removeContent(){
this.searchParams.content = ''
this.getGoodsListInfo()
}
此时,有问题,请求的路径的参数没有发生变化
如何解决该问题呢,应为search的路由对象没变化,此时我们需要去搞下路由对象
//删除面包屑的类别名称
removeCategoryName(){
this.searchParams.categoryName = ''
// 删除面包屑 路径 当中对应的类别名称还在
// 不能在这直接发请求,因为这样路由是不变化的
// 我们应该让路由去变化,发请求
// this.getGoodsListInfo();
this.$router.push({name:'search',params:this.$route.params})
},
//删除面包屑的关键字keyword
removeKeyword(){
this.searchParams.keyword = ''
this.$bus.$emit('clearKeyword') //使用全局时间总线通知header组件去清空关键字搜索框
// this.getGoodsListInfo();
this.$router.push({name:'search',query:this.$route.query})
},
注;参数一旦发生变化,监视的路由,就会自动执行,即可发送请求,而且请求路径也会发生变化
watch: {
$route() {
//还是要去准备参数再次发送请求,而这里的准备参数和beforMount内部是一模一样的
//因此我们可以把处理参数的过程封装一个公共的函数
this.handlerSearchParams()
//需要再次发送请求获取新的参数搜索的数据
this.getGoodsListInfo();
}
},
四,全局事件总线解决面包屑的关键字同时清空搜索框
1.在入口文件main.js,创建事件总线
beforeCreate() {
Vue.prototype.$bus = this
},
2.在header组件中,对于搜索框的关键字清空,
五,根据品牌搜索牵扯子向父通信(自定义事件)
1.searchSelector组件向父组件search传递数据,一点击品牌,就要父子通信, 根据品牌过滤商品信息
<ul class="logo-list"> <li v-for="(trademark, index) in trademarkList" :key="trademark.tmId" @click="$emit('searchForTrademark',trademark)">{{trademark.tmName}}</li> </ul>
父组件search
searchForTrademark(trademark){
//注意:参数格式,跟新处理数据
this.searchParams.trademark = `${trademark.tmId}:${trademark.tmName}`
//发送请求
this.getGoodsListInfo();
},
2.将品牌关键字,放入面包屑中,删除面包屑,重新处理数据,发送请求
<!-- trademark是字符串 如,'1:小米' --> <li class="with-x" v-if="searchParams.trademark"> {{searchParams.trademark.split(':')[1]}} <i @click="removeTrademark">×</i> </li>
//删除面包屑的品牌
removeTrademark(){
this.searchParams.trademark = ''
this.getGoodsListInfo();
},
六,根据属性搜索牵扯子向父通信(自定义事件)
1.searchSelector组件向父组件search传递数据,一点击属性,就要父子通信
父组件接收数据
<SearchSelector @searchForTrademark="searchForTrademark" @searchForAttr="searchForAttr"/>
//根据属性去搜索
searchForAttr(attr,attrValue){
// "属性ID:属性值:属性名",props=["属性ID:属性值:属性名", "属性ID:属性值:属性名"]
this.searchParams.props.push(`${attr.attrId}:${attrValue}:${attr.attrName}`)
this.getGoodsListInfo();
},
2.将属性关键字,放入面包屑中,删除面包屑,重新处理数据,发送请求
<!-- props=["属性ID:属性值:属性名", "属性ID:属性值:属性名"] --> <li class="with-x" v-for="(prop, index) in searchParams.props" :key="index"> {{prop.split(':')[1]}} <i @click="removeProp(index)">×</i> </li>
//删除面包屑当中的属性
removeProp(index){
//删除点击的面包屑
this.searchParams.props.splice(index,1)
//发送请求
this.getGoodsListInfo();
}