尚硅谷VUE项目-前端项目问题总结05【api-vuex-组件通信-面包屑-排序】

search模块开发

1.静态页面

2.api

//获取search数据  /api/list  POST  需要传递多个参数
//当前接口,给服务器传递一个默认参数,至少是一个空对象
export const reqGetSearchInfo=(params)=>requests({url:'/list',method:'post',data:params})

//例子:
// {
//     "category3Id": "61",
//     "categoryName": "手机",
//     "keyword": "小米",
//     "order": "1:desc",
//     "pageNo": 1,
//     "pageSize": 10,
//     "props": ["1:1700-2799:价格", "2:6.65-6.74英寸:屏幕尺寸"],
//     "trademark": "4:小米"
//   }
/**请求方式两种:
 *     axios('get')
 *     axios({})
 * post用data,get用params
 */

测试接口是否有数据,在main.js中

import {reqGetSearchInfo} from '@/api/index'
//至少是一个空对象
console.log(reqGetSearchInfo({}),'12212');

3.vuex

store->search

//search组件模块的小仓库
import { reqGetSearchInfo } from "@/api/index";
const state={
    searchlist:{},
};
const mutations={
    GETSEARCHLIST(state,searchlist){
        state.searchlist=searchlist
    },
};
const actions={
    //第一个上下文对象context,第二个载荷
     async getSearchList({commit},params={}){
         //当reqGetSearchInfo在调用获取服务器数据时,至少传递一个参数(空对象)
         //params是当前用户派发actio时,第二个参数,传递过来的,至少是一个空对象
        let result=await reqGetSearchInfo(params)
        if(result.code==200){
            commit('GETSEARCHLIST',result.data)
        }
    },

};
//计算属性,在项目中,为了简化数据而生
const getters={};

export default {
    // namespaced:true,
    state,
    mutations,
    actions,
    getters,
}

可用getters处理数据:
state是分模块的,getters不分模块(如果开了命名空间请注意,会分模块)

开启了命名空间 …mapGetters([‘goodsList’])
开启了命名空间 …mapGetters(‘search’,[‘goodsList’])

在这里插入图片描述

//计算属性,在项目中,为了简化数据而生
// 可以把我们将来在组件中需要用的数据进行简化,将来组件在获取组件的时候就方便了
const getters={
    //当前形参state为当前仓库的state,而非大仓库的state
    attrsList(state){
        //如果服务器数据回来了,state.searchlist.attrsList是一个数组,
        //如果网络慢或者没网,state.searchlist.attrsList应该返回的是undefined了,所以加【】
        return state.searchlist.attrsList||[]
    },
    goodsList(state){
        return state.searchlist.goodsList||[]
    },
    trademarkList(state){
        return state.searchlist.trademarkList||[]
    },
};

  mounted() {//==》暂时写这里,之后封装一个函数,因为search不可能只执行一次
    //先测试接口返回的数据格式
      this.$store.dispatch("getSearchList", {});
      //用命名空间
      // this.$store.dispatch("search/getSearchList", {});
  },
   computed: {
    //普通用法
    // ...mapState({
    //   getSearchList: (state) => state.search.searchlist,
    // }),

    //getters用法:
    //没用命名空间[开启了命名空间的这样拿  ...mapGetters('search',['goodsList'])]

    //'attrsList','trademarkList'
    ...mapGetters(["goodsList"]),

    //用命名空间
    // ...mapGetters('search',['goodsList','attrsList','trademarkList'])
  },

4. search产品模块和search子组件SearchSelector模块

一个知识点:对象合并Object.assign(A, b,c)把b,c的值合并到A上

search模块

let A = {
            category1Id: "",
            category2Id: "",
            category3Id: "",
            categoryName: "",
            keyword: "",
            order: "",
            pageNo: 1,
            pageSize: 10,
            props: [],
            trademark: "",
        }
        let b={category1Id:'2'};
        let c={order:'4'};
        console.log(Object.assign(A,b,c));
 data() {
    return {
      searchParams: {
        category1Id: "",
        category2Id: "",
        category3Id: "",
        categoryName: "",
        keyword: "",
        order: "",
        pageNo: 1,
        pageSize: 10,
        props: [],
        trademark: "",
      },
    };
  },
  beforeMount() {
    //点击菜单或者搜索时,收集参数【发送请求之前获取参数在beforeMounted中进行】
    //复杂写法
    //  this.searchParams.category1Id=this.$route.query.categorqy1Id;
    //  this.searchParams.category2Id=this.$route.query.category2Id;
    //  this.searchParams.category3Id=this.$route.query.category3Id;
    //  this.searchParams.categoryName=this.$route.query.categoryName;
    //  this.searchParams.keyword=this.$route.params.keyword;

    //es6新增语法:合并对象【Object.assign】
    //在发送请求之前,把接口需要传递的参数进行整理
    Object.assign(this.searchParams, this.$route.query, this.$route.params);
  },
  mounted() {
    //在发送请求之前带给服务器参数【searchParams参数发生变化有数值带给服务器--searchParams】
    this.getData();
  },
  computed: {
    //普通用法
    // ...mapState({
    //   getSearchList: (state) => state.search.searchlist,
    // }),

    //getters用法:
    //没用命名空间[开启了命名空间的这样拿  ...mapGetters('search',['goodsList'])]

    ...mapGetters(["goodsList"]),

    //用命名空间
    // ...mapGetters('search',['goodsList','attrsList','trademarkList'])
  },
  watch: {
    //不是this.$route
    //监听路由信息是否发生变化,如果有变化则再次发送请求。
    $route(newValue, oldValue) {
      //this.searchParams无变化
      // console.log(this.searchParams);

      //发送请求之前,先把对应的1,2,3,级分类置空,让他接收下一次的三级id
      //分类名字categoryName不用清理,每一次路由变化的时候,都会赋予它新的值。
      //放到发送请求前面和后面都可以
      this.searchParams.category1Id=''
      this.searchParams.category2Id=''
      this.searchParams.category3Id=''

      //再次发送请求之前整理带给服务器的参数
      Object.assign(this.searchParams, this.$route.query, this.$route.params);
      this.getData();

      //置空放这也可以
    },
  },
  methods: {
    getData() {
      this.$store.dispatch("getSearchList", this.searchParams);
      //用命名空间
      // this.$store.dispatch("search/getSearchList", {});
    },
  },

注意:注意:不需要深度监听,他只是简单的对象形式{}

search子模块–SearchSelector

import { mapGetters } from "vuex"
  export default {
    name: 'SearchSelector',
    mounted(){
      //  this.$store.dispatch("getSearchList", {});
    },
    computed:{
      ...mapGetters(['attrsList','trademarkList'])
    },

  }

5 面包屑【含组件兄弟通信$bus,子父自定义事件】

1. 面包屑处理分类
删除面包屑时优化注意的点:

  removeCategoryName() {
      //参数置空,getData没有必须要传入的参数,可带可不带,越少越好;
      //所以将this.searchParams.categoryName = undefined;【即不向服务器传参】

      // this.searchParams.categoryName = "";
      // this.searchParams.category1Id='';
      // this.searchParams.category2Id='';
      // this.searchParams.category3Id='';

      this.searchParams.categoryName = undefined;
      this.searchParams.category1Id = undefined;
      this.searchParams.category2Id = undefined;
      this.searchParams.category3Id = undefined;
      
      // this.getData();//不需要再发请求,watch已发过请求

      //路由跳转,但不要把params删除了
      //if判断不需要了,watch监听,已经处理了。肯定为true
      // if (this.$route.params) {
      this.$router.push({ name: "search", params: this.$route.params });
      // }
    },

2. 面包屑处理关键字【搜索】
用到同级组件通信:
props:父子
自定义事件:子父
vuex:万能 【目前在用作仓库数据】
插槽:父子
pubsub-js:万能(vue很少用)
$bus【eventbus】:全局事件总线

1.1配置全局事件总线:
在main.js中

new Vue({
  render: h => h(App),

  //全局事件总线$bus配置
  beforeCreate(){
    Vue.prototype.$bus=this;
  },

  //注册路由:底下的写法是kv一致省略v,切router小写
  //注册路由信息,当这里书写router时,组件身上都拥有$route,$router属性
  router,
  //注册仓库,组件实例身上会多出一个$store属性
  store,
}).$mount('#app')

1.2 search的删除面包屑函数中:

 removeKeyword() {
      this.searchParams.keyword = undefined;
      // this.getData();  //不需要再发请求,watch已发过请求
      // if (this.$route.query) {//不用判断,都是true
        this.$router.push({ name: "search", query: this.$route.query });
      // }
      //通知兄弟组件Header清除关键字
      this.$bus.$emit("clear");
    },

1.3 header的mounted中:

 mounted(){
  //通过全局事件总线清除关键字
    this.$bus.$on('clear',()=>{
      this.keyword='';
    })
  },

2. 面包屑处理品牌信息
分类,关键字,品牌的显示用v-if;而属性值的显示用v-for【props数组形式】,且需要去重
点击品牌–》跳转到对应的品牌页【子传父,一般是直接传过来,然后在父组件处理
父组件:

  <SearchSelector @tradeMarkInfo="tradeMarkInfo"/>

   tradeMarkInfo(tradeMark){
      this.searchParams.trademark=`${tradeMark.tmId}:${tradeMark.tmName}`
      this.getData()
    },
   removetradeMark() {
      this.searchParams.trademark = undefined;
      //路由没跳转
      this.getData();
    },

子组件:

   methods:{
      tradeMarkHandler(trademark){
        this.$emit('tradeMarkInfo',trademark)
      },
    },

知识点:
1. 对象转换为字符串: 将数据{tmId: 6,tmName: “VIVO”}---------》处理数据为’6:VIVO’==== 》 用模板字符串
2. 字符串切割为另一个字符串:将数据’1:xxx’--------》处理数据为’xxx’============ 》split()将字符串切割成数组,选中哪一项
3. 字符串添加到数组中:将字符串格式"106:安卓手机:手机一级"—》处理为数组的内容[“106:安卓手机:手机一级”] : 把字符串push到数组里
4. 数组去重: xxx.indexOf(props)==-1
5. 删除数组信息this.searchParams.props.splice(index,1)

includes【数组和字符串都可】和indexOf差不多

//1. 将数据{tmId: 6,tmName: "VIVO"}--》处理数据为'1:xxx'
 tradeMarkInfo(tradeMark){
      this.searchParams.trademark=`${tradeMark.tmId}:${tradeMark.tmName}`
      this.getData()
    },

//2. 将数据'1:xxx'--》处理数据为'xxx'
 <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.keyword">
              {{ searchParams.keyword }}<i @click="removeKeyword">×</i>
            </li>
             <!-- 品牌的面包屑 -->
            <li class="with-x" v-if="searchParams.trademark">
              {{ searchParams.trademark.split(":")[1] }}<i @click="removeKeyword">×</i>
            </li>
          </ul>

//3. 将字符串格式"106:安卓手机:手机一级"---》处理为数组的内容["106:安卓手机:手机一级"]
 attrInfo(attr, attrValue) {
      //['属性ID1:属性值1:属性名1',''属性ID2:属性值2:属性名2'']
      let props=`${attr.attrId}:${attrValue}:${attr.attrName}`
      this.searchParams.props.push(props)
      this.getData()
    },

//4.  数组去重,if判断,只有一行代码,可省略{}
      if(this.searchParams.props.indexOf(props)==-1){
        this.searchParams.props.push(props)
      }
//5. 删除数组信息:splice
removeAttr(index){
      //删除售卖的属性值
      this.searchParams.props.splice(index,1)
      this.getData()
    },

6. 排序

综合:1.asc 2.desc
价格:1.asc 2.desc
包含可用:indexOf和includes

active选中类:

 <ul class="sui-nav">
    <li :class="{active:searchParams.order.indexOf('1')!=-1}">
//<li :class="{active:searchParams.order.includes('1')}">
        <a href="#">综合</a>
    </li>
    <li :class="{active:searchParams.order.indexOf('2')!=-1}">
       <a href="#">价格⬆</a>
    </li>           
</ul>

在标签里写一大串,可以封装在computed里:

 <ul class="sui-nav">
     <!-- <li :class="{active:searchParams.order.indexOf('1')!=-1}"> -->
     <li :class="{ active: isOne }">
         <a href="#">综合</a>
     </li>
     <li :class="{ active: isTwo }">
         <a href="#">价格⬆</a>
     </li>
 </ul>

 computed: {
    isOne() {
      return this.searchParams.order.indexOf("1") != -1;
    },
    isTwo() {
      return this.searchParams.order.indexOf("2") != -1;
    },
  },

选中箭头
引入iconfont:
1.添加项目选font-class,用在线链接:在public下引入

<!-- 引入iconfont -->
<link rel="stylesheet" href="https://at.alicdn.com/t/font_3277412_5u3t7cla0ut.css">
<link rel="stylesheet" href="http://at.alicdn.com/t/font_3277412_5u3t7cla0ut.css">

2.组件中引用

<ul class="sui-nav">
    <!-- <li :class="{active:searchParams.order.indexOf('1')!=-1}"> -->
    <li :class="{ active: isOne }">
       <a href="#">综合<span v-show="isOne"  class="iconfont" :class="{'icon-sort-up':isAsc,'icon-sort-down':isDesc}"></span></a>
                  
     </li>
     <li :class="{ active: isTwo }">
        <a href="#" >价格<span v-show="isTwo"  class="iconfont" :class="{'icon-sort-up':isAsc,'icon-sort-down':isDesc}"></span></a>
                  
     </li>
</ul>

切换排序

 <ul class="sui-nav">
                <!-- <li :class="{active:searchParams.order.indexOf('1')!=-1}"> -->
                <li :class="{ active: isOne }" @click="changeOrder('1')">
                  <a href="#"
                    >综合<span
                      v-show="isOne"
                      class="iconfont"
                      :class="{
                        'icon-sort-up': isAsc,
                        'icon-sort-down': isDesc,
                      }"
                    ></span
                  ></a>
                </li>
                <li :class="{ active: isTwo }" @click="changeOrder('2')">
                  <a href="#"
                    >价格<span
                      v-show="isTwo"
                      class="iconfont"
                      :class="{
                        'icon-sort-up': isAsc,
                        'icon-sort-down': isDesc,
                      }"
                   ></span
            ></a>
   </li>
</ul>

    changeOrder(flag) {
      let originOrder=this.searchParams.order;
      let newOrder='';

      let originFlag=this.searchParams.order.split(':')[0];
      let originSort=this.searchParams.order.split(':')[1];
    
      if(flag==originFlag){
        newOrder=`${originFlag}:${originSort=='desc'?'asc':'desc'}`
      }else{
      newOrder=`${flag}:${'desc'}`
      }
      this.searchParams.order=newOrder
      this.getData()
    },
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Vue面包屑动态显示,可以按照以下步骤进行操作: 1. 首先,在`src`文件夹下的`components`文件夹新建一个名为`Breadcrumb.vue`的文件。[2] 2. 在`Breadcrumb.vue`文件,将以下代码复制粘贴进去: ```html <template> <div> <el-breadcrumb separator="/"> <el-breadcrumb-item v-for="(v, i) in breadList" :key="i" :to="v.meta.path"> {{ v.meta.title }} </el-breadcrumb-item> </el-breadcrumb> </div> </template> <script> export default { data() { return { breadList: [], }; }, watch: { $route() { this.getBreadcrumb(); }, }, methods: { isHome(route) { return route.name === "home"; }, getBreadcrumb() { let matched = this.$route.matched; if (!this.isHome(matched<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Vue实现动态面包屑](https://blog.csdn.net/weixin_51497206/article/details/118599173)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [vue实现动态面包屑](https://blog.csdn.net/weixin_48398799/article/details/119981153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值