zoukankan      html  css  js  c++  java
  • vue前台(五)

    一,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();
        }
     
  • 相关阅读:
    PAT1064(上)分析部分
    网络支付极其简单的体会
    L3,please send me a card
    PAT1008
    里氏转换
    数组遍历问题
    注册登录界面(简陋版)
    表单事件,onblur,onfocus,焦点
    复制所有链接,全选,反选
    剪切板
  • 原文地址:https://www.cnblogs.com/fsg6/p/13346532.html
Copyright © 2011-2022 走看看