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

尚硅谷VUE项目-前端项目问题总结05

  • search模块开发
    • 1.静态页面
    • 2.api
    • 3.vuex
    • 4. search产品模块和search子组件SearchSelector模块
    • 5 面包屑【含组件兄弟通信$bus,子父自定义事件】
    • 6. 排序

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’])

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

//计算属性,在项目中,为了简化数据而生
// 可以把我们将来在组件中需要用的数据进行简化,将来组件在获取组件的时候就方便了
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}">
//
  • <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()
        },
    

    你可能感兴趣的:(vue.js,javascript,前端)