zl程序教程

您现在的位置是:首页 >  前端

当前栏目

vue前台(五)

Vue 前台
2023-09-11 14:20:08 时间

一,search组件的静态页面实现以及数据获取到vuex内

之前在home页,点击商品分类列表,跳转到search页,在search页我们需要获取数据,根据接口文档,需要一些请求参数,我们可从search组件的路由对象的query,params参数
获取需要的请求参数,然后在beforemounted中处理参数(此时已经初始化data参数了),然后在mounted中dispatch到vuex,将处理的请求参数传递过去。

1.1请求体参数searchParams需要初始化,重要

  category1Id: "",  category2Id: "",   category3Id: "", categoryName: "",是typenav组件传递过来的query参数,
keyword: "", 是header组件传递过来的params参数
接口文档需要的参数

 

 

         
 data() {
    return {
      //初始化搜索参数(收集搜索参数)
      //为搜索请求提供搜索参数
      searchParams: {
        category1Id: "",
        category2Id: "",
        category3Id: "",
        categoryName: "",
       : "",
        order: "1:desc",
        pageNo: 1,
        pageSize: 5,
        props: [],
        trademark: ""
      }
    };
  },

1.2.在search组件中,对searchParams数据进行处理后,然后在发送ajax请求,此时需要在beforeMount()期间处理searchParams数据,因为在该组件期间,data的数据已经获取到了

//对新对象过滤,对为空的属性过滤
    Object.keys(searchParams).forEach(item=> {
      if(!searchParams[item]){
        delete searchParams[item]
      }
    })
  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全情体数据,然后再次发送请求,

2.对searchParams参数的整理流程封装成函数,复用, search组件页面mounted加载后,需要发送一次请求, 如果路由参数一变化,又要整理数据,发送一次请求
 
处理方式;
 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

注意;

//   如果在组件中,获取数据,a.b.c,可能读取不到,报错“Error in render: "TypeError: Cannot read property '0' of undefined"
// 模板在渲染时,获取不到属性值,解决方式,在vuex中getters配置,获取不到时返回空数组,此时就不会报错

 

 

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
}

 

3.然后在总的vuex中注册下
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules:{
    home,
    search
  }
})

 

4.在search组件中获取数据

import { mapGetters } from "vuex";
 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的数据

import {mapGetters} from '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>

 

 

四,面包屑展示类名和关键字
 
1.在search组件,填充面包屑数据, 如果search页中有params或者query参数,就显示,没有就不显示
 <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组件中,对于搜索框的关键字清空, 

 

mounted(){
    this.$bus.$on('clearKeyword',this.clearKeyword)
  },
 
clearKeyword(){
      this.keyword = ''
    }
 
在search组件中,触发clearKeyword事件,通知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();
    }