尚品汇学习

450 阅读1分钟

 1.设置@为src文件,便于在之后引入时方便操作。

        在根目录下建立jsconfig.json文件,将如下代码放进去。

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "exclude": ["node_modules", "dist"]
}

2.拆解页面结构

        将Header和Footer这种始终非路由组件,放在components文件夹下,建立相应文件夹,内部装有Header.vue文件。

        至于路由组件,在src文件夹下建立pages文件夹,将对应路由组件放在此文件夹下。

3.搭建组件的注意点

        1.在移动代码时,要注意样式和图片。关于样式,因为本项目利用less书写样式,在引入时,加上lang="less"。对于图片,在相应文件夹下建立images文件夹。

        2.不要忘记将reset.css,移动到public文件夹下,并引入,才能此样式生效。

4.实现Footer组件只在Home和Search组件下显示        

<Footer v-show="$route.meta.show"/>    //利用route中的meat属性
{
    path:'/home',
    component:Home,
    meta:{show:true}
}

5.编程式路由导航

        定义一个方法,使用push,如果需要传参,在后面加相应参数即可(params记得占位)

this.$router.push({
    name:'search',
    params:{keyword:'你好啊'}
    query:{k:this.keyword}    // query传参是键值对的形式
})

6.如何指定params参数可传可不传,如果传递空串如何解决?

        在配置路由时,在占位的后面加上一个问号即可实现。

path:'/search/:keyword?'

        传递空串的时候,用undefined解决问题。

this.$router.push({
    name:'search',
    params:{keyword:'' || undefined}
})

7.多次点击按钮传参会报错,如何解决?

        重写push方法,如果resolve或者reject没有回调函数,则添加一个回调即可。

import VueRouter from 'vue-router'
//重写push方法
let originPush = VueRouter.prototype.push
VueRouter.prototype.push = function(location,resolve,reject){
    if(resolve && reject){
        originPush.call(this,location,resolve,reject)
    } else{
        originPush.call(this,location,()=>{},()=>{})
    }
}

8.三级联动组件声明为全局组件

//全局注册组建
import TypeNav from '@/components/TypeNav'
//  传递两个参数(组件的名字,哪一个组件)
Vue.component(TypeNav.name,TypeNav)

        全局组件注册完成后,在引入时不需要import和声明components

9.对于axios进行二次封装

        在src文件夹下建立api文件夹,创建request.js文件。

        1.设置baseURL和timeout

import axios from "axios";
const requests = axios.create({
    baseURL:'/api',
    timeout:5000    //访问大于5s取消
})

        2.设置请求拦截器和响应拦截器。

//引入nprogress
import nprogress from "nprogress";
//引入nprogress样式
import 'nprogress/nprogress.css'

//设置请求拦截器,并且加上进度条。
requests.interceptors.request.use(function (config) {
    nprogress.start()
    return config;
}, function (error) {
    return Promise.reject(error);
});

// 设置响应拦截器
requests.interceptors.response.use(function (response) {
    nprogress.done()
    return response.data;
}, function (error) {
    return Promise.reject(error);
});

10.API接口统一管理

        在api文件夹下建立index.js

import requests from './request'
//三级联动axios发请求
export const reqCategoryList = () => 
    requests({ url: 'product/getBaseCategoryList', method: 'get' })

        设置访问接口函数后,在main.js中引入

//  引入reqCategoryList
import {reqCategoryList} from  '@/api'

        进行跨域代理操作,实现本地接口与目标接口连接

//配置代理跨域
    devServer: {
        proxy: {
            "/api": {
                target: "http://39.98.123.211",
            },
        },
    },

11.使用vuex完成三级联动

        1.如果项目过大,state内数据过多不便查看,可以在store文件夹下设置小库再引入。引入时不再引入state,而是引入modules:{home,search}

//创建action,mutation,state,getter对象
const state = {
    a:1
}
const actions = {}
const mutations = {}
const getters = {}

export default {
    actions,
    mutations,
    state,
    getters
}
import Vue from 'vue'
import Vuex from 'vuex'
//引入小仓库
import home from './home'
import search from './search'
Vue.use(Vuex)
export default new Vuex.Store({
    actions,
    mutations,
    modules: {
        home,
        search,
    },
    getters
})

        2.配置vuex,在home.js中完成请求数据。

//引入请求数据的函数,分别暴露一定要记得加{}
import {reqCategoryList} from  '@/api'
//创建action,mutation,state,getter对象
const state = {
    categoryList:[]
}
const actions = {
//reqCategoryList()请求回来是一个Promise函数,所以用async和await
    async categoryList({commit}){
       let result =  await reqCategoryList()    
       if(result.code == 200){    //如果请求成功,result.code就是200
           commit('CATEGORYLIST',result.data)    
       }
    }
}
const mutations = {
    CATEGORYLIST(state,categoryList){
        state.categoryList = categoryList    //将数据交给state
    }
}
const getters = {
    
}

export default {
    actions,
    mutations,
    state,
    getters
}

        3.在TypeNav中配置计算属性,再在页面中使用。

import { mapState } from "vuex"; //引入mapState要记得加{}!烦死了
 computed: {
    ...mapState({
      categoryList: (state) => state.home.categoryList,
    }),    //vuex会传递state到函数中,得到下面小库中的内容即可
  },

        4.对于1级、2级、3级标题进行遍历,得到所有标题

v-for="(c1, index) in categoryList" :key="c1.categoryId"
v-for="(c2, index) in c1.categoryChild" :key="c2.categoryId"
v-for="(c3, index) in c2.categoryChild" :key="c3.categoryId"

        5.利用js设置hover效果:对于h标题添加@mouseenter和@mouseleave事件传递参数(index),设置this.currentIndex = index;(记得设置初始currentIndex = -1)

  为父盒子div设置动态类:class="{ cur: currentIndex == index }"

  最后设置cur的backgroudcolor,即可实现hover效果。

       6.利用js实现2、3级标题的显示与隐藏:为2级标题设置动态style。

:style="{display:currentIndex == index? 'block' : 'none'}"

12.点击商品分类,给search传递参数

难点:需要知道到底是点的是不是a标签(如果不是就不传),是哪个a标签。

1.首先将每个a标签上都添加一个统一的自定义属性名,便于我们判断是否点击的是a标签。

:data-categoryName="c2.categoryName"

2.将每个a标签上也添加一个各自的id属性,便于我们判断点击的是几级标签。

:data-category2Id = "c2.categoryId"

3.给div设置一个goSearch方法,配置方法。

goSearch(event) {
      //  得到点击事件的标签,比如点了h1标签a就是h1标签。
      let a = event.target;
      //  通过解构赋值得到自定义属性值,属性值都是小写的,这里要注意。
      let {categoryname,category1id,category2id,category3id} = a.dataset
      //因为点击的a标签上都有categoryname,所以做if判断
      if(categoryname){
        //  准备需要传参的数据
        let location = {name:'search'}
        let query = {categoryName:categoryname}
        //  如果是点击1级标题就带一级id,之后同理
        if(category1id){
          query.category1Id = category1id
        } else if(category2id){
          query.category2Id = category2id
        }else if(category3id){
          query.category3Id = category3id
        }
        location.query = query
        //判断一下有没有params参数,如果有也放在location里
        if(this.$route.params){
          location.params = this.$route.params
        }
        //  路由跳转
        this.$router.push(location)
      }
    },