Vue 前台项目(电商)8

vuex 模块式开发

vuex 是官方提供的一个插件,状态管理库,集中式管理项目中组件共用的数据。
如果项目很小,完全不需要 vuex
如果项目很大,组件很多、数据很多、数据维护很费劲,就用 vuex

安装 vuex

npm install --save vuex

vuex的基本使用
在 src 文件夹下创建 store 文件夹,并在里面创建 home 文件夹、search 文件夹和相应的 index.js 文件
在这里插入图片描述
home/index.js

//home 模块的小仓库
//state:仓库存储数据的地方
const state = {};
//mutations:修改state的唯一手段
const mutations = {};
//actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {};
//getters:理解为计算属性,用于简化仓库数据,让组件获取仓库数据更加方便
const getters = {};
 export default{
    state,
    mutations,
    actions,
    getters
 }

search/index.js

//search 模块的小仓库
const state = {}
const mutations = {}
const actions = {}
const getter = {}
 export default{
    state,
    mutations,
    actions,
    getter
 }

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
//需要使用插件一次
Vue.use(Vuex);
//引入小仓库
import home from './home'
import search from './search'

//对外暴露 Store 类的一个实例
export default new Vuex.Store({
    //实现Vuex仓库模块式开发存储数据
    modules:{
        home,
        search
    }
})

打开 main.js 把 store仓库 引入
在这里插入图片描述
为了规范写法,我们将 pages > Home >TypeNav 文件夹移动到 conponents 文件夹里
ps:全局组件放在 components 文件夹里

同时将 main.js 里引入 TypeNav 的路径改为

import TypeNav from '@/components/TypeNav'

实现 三级联动组件 TypeNav 动态渲染数据

将 请求到的数据放到 store > home 模块的小仓库中

TypeNav / index.vue
在这里插入图片描述
home / index.js

//home 模块的小仓库

import { reqCategoryList } from "@/api";

//state:仓库存储数据的地方
const state = {
   //根据接口返回值初始化,返回的是对象,就是{} 返回的是数组,就是[]
   categoryList:[]
};
//mutations:修改state的唯一手段
const mutations = {
   CATEGORYLIST(state,categoryList){
      state.categoryList = categoryList
   }
};
//actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {
   //通过API里面的接口函数调用,向服务器发送请求,获取服务器的数据
    async categoryList({commit}){
       let result = await reqCategoryList()
       if(result.code==200){
          commit("CATEGORYLIST",result.data)
       }
   }
};
//getters:理解为计算属性,用于简化仓库数据,让组件获取仓库数据更加方便
const getters = {};
 export default{
    state,
    mutations,
    actions,
    getters
 }

数据拿到之后就可以渲染页面了

TypeNav / index.vue

<template>
  <!-- 商品分类导航 -->
    <div class="type-nav">
        <div class="container">
            <div @mouseleave="leaveIndex">
            <h2 class="all">全部商品分类</h2>
            <div class="sort">
                <div class="all-sort-list2">
                    <div class="item" v-for="(c1,index) in categoryList" :key="c1.categoryId" :class="{cur:currentIndex==index}">
                        <h3 @mouseenter="changeIndex(index)">
                            <a href="">{{c1.categoryName}}</a>
                        </h3>
                        <div class="item-list clearfix">
                            <div class="subitem" v-for="c2 in c1.categoryChild" :key="c2.categoryId">
                                <dl class="fore">
                                    <dt>
                                        <a href="">{{c2.categoryName}}</a>
                                    </dt>
                                    <dd>
                                        <em v-for="c3 in c2.categoryChild" :key="c3.categoryId">
                                            <a href="">{{c3.categoryName}}</a>
                                        </em>
                                    </dd>
                                </dl>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            </div>
            <nav class="nav">
                <a href="###">服装城</a>
                <a href="###">美妆馆</a>
                <a href="###">尚品汇超市</a>
                <a href="###">全球购</a>
                <a href="###">闪购</a>
                <a href="###">团购</a>
                <a href="###">有趣</a>
                <a href="###">秒杀</a>
            </nav>

        </div>
    </div>
</template>

<script>
import {mapState} from 'vuex'
export default {
    name:'TypeNav',
    data(){
        return{
            //存储用户鼠标移上哪一个一级分类
            currentIndex:-1
        }
    },
    //组件挂载完毕:可以向服务器发送请求
    mounted(){
        //通知Vuex发请求,获取数据,存储于仓库当中
        this.$store.dispatch('categoryList')
    },
    computed:{
        ...mapState({
            //右侧需要的是一个函数,当使用这个计算属性的时候,右侧函数会立即执行一次
            //注入一个参数 state ,其实即为大仓库中的数据
            categoryList:state=>state.home.categoryList
        })
    },
    methods:{
        //鼠标进入 修改响应式数据 currentIndex 属性
        changeIndex(index){
            //index:鼠标移上某一个一级分类的元素的索引值
            this.currentIndex = index
        },
        //一级分类鼠标移除的时间回调
        leaveIndex(){
            //鼠标移出 currentIndex ,变为-1
            this.currentIndex = -1
        }
    }
}
</script>

<style scoped lang="less">
.type-nav {
        border-bottom: 2px solid #e1251b;

        .container {
            width: 1200px;
            margin: 0 auto;
            display: flex;
            position: relative;

            .all {
                width: 210px;
                height: 45px;
                background-color: #e1251b;
                line-height: 45px;
                text-align: center;
                color: #fff;
                font-size: 14px;
                font-weight: bold;
            }

            .nav {
                a {
                    height: 45px;
                    margin: 0 22px;
                    line-height: 45px;
                    font-size: 16px;
                    color: #333;
                }
            }

            .sort {
                position: absolute;
                left: 0;
                top: 45px;
                width: 210px;
                height: 461px;
                position: absolute;
                background: #fafafa;
                z-index: 999;

                .all-sort-list2 {
                    .item {
                        h3 {
                            line-height: 30px;
                            font-size: 14px;
                            font-weight: 400;
                            overflow: hidden;
                            padding: 0 20px;
                            margin: 0;

                            a {
                                color: #333;
                            }
                        }

                        .item-list {
                            display: none;
                            position: absolute;
                            width: 734px;
                            min-height: 460px;
                            background: #f7f7f7;
                            left: 210px;
                            border: 1px solid #ddd;
                            top: 0;
                            z-index: 9999 !important;

                            .subitem {
                                float: left;
                                width: 650px;
                                padding: 0 4px 0 8px;

                                dl {
                                    border-top: 1px solid #eee;
                                    padding: 6px 0;
                                    overflow: hidden;
                                    zoom: 1;

                                    &.fore {
                                        border-top: 0;
                                    }

                                    dt {
                                        float: left;
                                        width: 54px;
                                        line-height: 22px;
                                        text-align: right;
                                        padding: 3px 6px 0 0;
                                        font-weight: 700;
                                    }

                                    dd {
                                        float: left;
                                        width: 415px;
                                        padding: 3px 0 0;
                                        overflow: hidden;

                                        em {
                                            float: left;
                                            height: 14px;
                                            line-height: 14px;
                                            padding: 0 8px;
                                            margin-top: 5px;
                                            border-left: 1px solid #ccc;
                                        }
                                    }
                                }
                            }
                        }

                        &:hover {
                            .item-list {
                                display: block;
                            }
                        }
                    }
                    .cur{
                        background-color: skyblue;
                    }
                }
            }
        }
    }
</style>

引入防抖与节流

防抖:就是规定在一段时间内,事件只执行一次,如果在规定的时间里面,再次触发该事件,那么将会重新计时
例子:老师告诉学生们,如果在一个星期内不会上课睡觉,就奖励一颗棒棒糖,如果在这段时间内,有人违规了,那么就从这一刻开始重新计时,过一个星期就可以领到棒棒糖了
节流:规定在一段时间内执行一次
例子:老师告诉学生们,一周内在课堂上只允许放一次影片观看,如果在这一周内观看了一次影片,那么接下来学生观看电影的请求,老师都不会答应的

在这里插入图片描述

一级,二级,三级分类的跳转

我们采用编程式导航 + 事件委托 来进行路由跳转
存在的一些问题:事件委托,是把全部的子节点【h3,dt,dl,em】的事件委托给父亲节点
点击 a 标签的时候,才会进行路由跳转【怎么确定点击的一定是a标签】
存在另一个问题:即使你能确定点击的是a标签,如何区分是一级、二级、三级分类的标签

我们的解决方式如下图:
在这里插入图片描述
在这里插入图片描述

开发Search模块中的TypeNav商品分类菜单(过渡动画效果)

在Home路由页面 商品分类是默认打开的
在Search路由页面 商品分类是默认关闭的
实现,如下图:
在这里插入图片描述
在这里插入图片描述
在Search页面时,鼠标移入商品分类,展开,移出时,则关闭 且不影响Home页面
实现,如下图:
在这里插入图片描述
在这里插入图片描述
添加过渡动画
实现,如下图:
在这里插入图片描述
s

TypeNav商品分类列表的优化

因为 Home 组件和 Search 组件都用到 TypeNav 组件了
所以会导致重复的向服务器发送两次请求
优化方式:在根组件发送请求
TypeNav
在这里插入图片描述
这行代码剪切到根组件(App.vue)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值