笨鸟学习日记之Vue项目篇------仿蘑菇街商城

361 阅读5分钟

仿蘑菇街移动端练手项目------第一阶段心得总结

技术栈

  • vue@2.6.11
  • vue-router@3.2.0
  • vuex@3.4.0
  • axios(网络封装)
  • better-scroll@2.3.0(页面滑动)
  • vue-lazyload@1.3.3(图片懒加载)

项目介绍

一个移动端仿蘑菇街线上商城,分为首页的展示、商品详细信息的展示、商品分类信息的展示、购物车商品信息的战术以及添加购物车的功能四个部分。项目的核心在于组件的封装思想、父子组件间的通讯与事件监听以及请求接口信息的处理与展示。不足点:没有进行登录注册以及购买界面的相关逻辑设计,未使用UI框架,设计出来的UI界面美观度还待提升。

架构

  • vue-cli 4搭建整体框架
  • vue-router进行前端路由
  • vuex进行状态管理
  • axios进行资源请求
  • github地址:github.com/liangmingyu…

项目目录结构

image-20210512153844251.png

原来是这样噢

1>着手去开始一个项目的话切入点

  • 本项目为移动端商城项目,常用normalize.css文件来代替CSS reset 它让不同的浏览器在渲染页面元素的时候形式更统一。
  • 不管对于PC端还是移动端,先对页面样式进行格式化,于是创建一个base.css文件用于对于页面元素进行初始化(包括了a标签的字体颜色以及下划线、li的前面的小点)
  • 两者css文件可以在其中一个导入另外一个文件,之后再入口文件main.js管理的APP.vue文件的样式中使用@import引入,这样做的目的在于在webpack打包时可以随着进行转化。

2>脚手架的配置

// 引入path模块
const path = require('path')
function resolve(dir) {
  // path.join(__dirname)设置绝对路径
  return path.join(__dirname, dir)
}
module.exports = {
  chainWebpack: config => {
    // 起别名 便于读取文件的路径
    config.resolve.alias
      .set('@', resolve('./src'))
      .set('assets', resolve('./src/assets'))
      .set('components', resolve('./src/components'))
      .set('router', resolve('./src/router'))
      .set('views', resolve('./src/views'))
      .set('network', resolve('./src/network'))
      .set('common', resolve('./src/common'))
  },
}

3>组件的封装

  • MainTabBar的封装

    • 1.分析:在首页、分类、购物车、我的四个页面都存在这个组件

    • 2.实践:先封装一个TabBar可用于其他类似项目的开发,再包装一个MainTabBar组件引入APP.vue中即可

    • 3.get知识点:

      • 1.具名插槽的使用

        • (1)在使用插槽时给定一个name属性

          <template>
            <div class="nav-bar">
              <div class="left"><slot name="left"></slot></div>
              <div class="center"><slot name="center"></slot></div>
              <div class="right"><slot name="right"></slot></div>
            </div>
          </template>
          
        • (2)使用时给定属性slot为插槽名称

          <nav-bar class="home-nav">
            <div slot="center">购物街</div>
          </nav-bar>
          
      • 2.tab栏的切换思想

        • (1)关键点在于需要一个属性currentIndex来记录当前的选定的选项卡

          • data () {
                return {
                  currentIndex: 0
                }
            },
            
        • (2)动态绑定类名使用对象进行赋值判断

          <div
                v-for="(item, index) in titles"
                :key="index"
                class="tab-control-item"
                @click="tabClick(index)"
                :class="{ active: index === currentIndex }"
              >
                <span>{{ item }}</span>
          </div>
          
          .active span {
            color: var(--color-tint);/* 在base.css中在root中声明了该变量 */
            border-bottom: 3px solid var(--color-tint);
          }
          
      • 3.vue-router的基本使用和配置(routeroute和router的区别)

        • $route存储的是当前路由的配置信息对象(path属性)

        • $router存储的是所有的路由信息对象,可调用push、replace方法进行页面路由的切换

        • vue-router的配置

          • 1.安装vue-router

            1)在vue-cli中
            vue add router
            2)包管理工具中
            npm i vue-router -S
            
          • 2.导入vue-router

            import VueRouter from 'vue-router'
            
          • 3.安装vue-router

            Vue.use(VueRouter);
            
          • 4.配置vue-router并导出router对象

            //router/index.js
            const routes = [
                {
                    path:'/home',//路径
                	component:()=>import('view/home/Home.vue')//懒加载方式导入组件
                }
            ]
            const router = new VueRouter({
              mode: 'history',//使用history模式使用this.$router.push()方法即可跳转路由
              base: process.env.BASE_URL,
              routes
            })
            export default router
            
          • 5.在main.js中导入router对象挂载到Vue中

            //router/main.js
            import router from './router'
            new Vue({
              router,
              render: h => h(App)
            }).$mount('#app')
            
  • 首页视图组件的封装

    • 1.分析:首页页面结构分别为轮播图模块、好物推荐模块、本周流行模块、商品展示板块。

    • 2.实践:为了是目录结构更加清晰,创建子目录childrenComps为了将首页的结构进行组件化管理,将把这些组件抽离放入该目录中。组件一一对应进行编写实现模块化开发。

    • 3.get知识点:

      • (1)axios的基本使用(网络封装、利用Promise对响应数据的进行处理)

        • 1.安装axios

          npm i axios -S
          
        • 2.导入axios

          import axios from 'axios'
          
        • 3.对axios在封装一层,防止更换其他框架重构整个项目代码

          //network/request.js
          import axios from 'axios'
          export function instance (config) {
            // axios.create方法创建实例
            const instance = new axios.create({
              // 设置baseURL作用是之后输入路径地址即可 省略了前面的重复书写
              baseURL: '请求地址',
              timeout: 5000//设置超时时间
            })
            // axios本身就是用promise包裹起来的 直接进行返回即可
            return instance(config)
          }
          
        • 4.封装首页网络请求函数

          //network/home.js
          import { instance } from './request'
          export function getGoodsData (type, page) {
            return instance1({
              url: 'home/data',
              params: {
                type,
                page
              }
            })
          }
          
    • (2)better-scroll的基本配置与使用

      <template>
        <div class="wrapper" ref="wrapper">
          <div class="content">
            <slot></slot>
          </div>
        </div>
      </template>
      <script>
      import BScroll from "@better-scroll/core";
      import Pullup from "@better-scroll/pull-up";
      import ObserveDOM from "@better-scroll/observe-dom";
      import ObserveImage from "@better-scroll/observe-image";
      import MouseWheel from "@better-scroll/mouse-wheel";
      // 安装插件
      BScroll.use(Pullup);
      BScroll.use(ObserveDOM);
      BScroll.use(ObserveImage);
      BScroll.use(MouseWheel);
      mounted() {
          // 这时候获取元素不用DOM操作获取 避免命名冲突
          // 使用vue 给我们提供的$refs
          //  this.$nextTick 是一个异步函数,为了确保 DOM 已经渲染找得到
          this.$nextTick(() => {
            this.scroll = new BScroll(this.$refs.wrapper, {
              observeDOM: true,
              mouseWheel: true,
              probeType: this.probeType,
              click: true,
              pullUpLoad: this.pullUpLoad,
            });
      	  //监听滚动
            this.scroll.on("scroll", (position) => {
              this.$emit("scroll", position);
            });
      	  //监听上拉加载更多
            this.scroll.on("pullingUp", () => {
              this.$emit("pullingUp");
            });
          });
        }
      </script>
      
    • (3)goods的结构的巧妙设计

      goods: {
        pop: {
          page: 0,
          list: [],
        },
      new: {
          page: 0,
          list: [],
        },
      sell: {
          page: 0,
          list: [],
        },
      },
      
    • (4)keep-alive的基本使用(利用触发的生命周期钩子函数activated 和 deactivated钩子函数保存和恢复滑动的长度,解决在进行页面路由时不会重新创建导致的页面返回最顶部问题)

      /*APP.vue*/
      <keep-alive exclude="Detail">
            <router-view />
      </keep-alive>
      
      
      /*Home.vue*/
      activated() {
          this.$nextTick(() => {
            // 首页处于活跃状态下开启轮播图定时器
            this.$refs.homeSwiper && this.$refs.homeSwiper.startTimer();
          });
        },
        deactivated() {
          // 保存离开home时的滑动长度y
          this.saveY = this.$refs.scroll.getScrollY();
          // 首页处于不活跃状态下关闭轮播图定时器
          this.$nextTick(() => {
            // 首页处于活跃状态下开启轮播图定时器
            this.$refs.homeSwiper && this.$refs.homeSwiper.stopTimer();
          });
        },
      
  • 购物车视图组件的封装

    • 1.分析:购物车页面的结构分别为顶部导航模块、商品展示模块、底部工具栏模块

    • 2.实践:同首页

    • 3.get知识点:

    • (1)vuex的基本使用(以及mapGetters,mapActions辅助函数的使用)

      • 1.安装vuex

        npm i vuex -S
        
      • 2.导入vuex

        import Vuex from 'vuex'
        
        import actions from './actions'
        import mutations from './mutations'
        import modules from './modules'
        import getters from './getters'
        
        // 1.安装vuex
        Vue.use(Vuex);
        
        const state = {
          cartList: []
        }
        2.创建Store的实例对象并导出
        export default new Vuex.Store({
          state,
          mutations,
          actions,
          getters,
          modules
        })
        
  • 商品详情视图组件的封装

    • 1.分析:商品详情页的结构分别为顶部导航模块、商品轮播图模块、商品信息模块、商品图片展示模块、商品规格模块、商品评论模块、相似商品推荐模块

    • 2.实践:同首页

    • 3.get知识点:

      • (1)backTop组件mixin的使用(实际开发中不推荐使用,因为会容易造成重名问题)

        //common/mixin.js
        const BackTop = () => import('components/content/backtop/BackTop');
        export const backTopMixin = {
          components: {
            BackTop
          },
          data() {
            return {
              isShowBackTop: false
            }
          },
          methods: {
            backClick() {
              this.$refs.scroll.scrollTo(0, 0)
            },
            showBackTop(position) {
              this.isShowBackTop = -position.y > 1000
            }
          }
        }
        
        // Home.vue
        export default {
        	mixins: [backTopMixin]
        }
        
      • (2)抽取了Goods、Shop、GoodsParam类便于数据请求的接收

        // 定义商品类
        export class Goods {
          constructor (itemInfo, columns, services) {
            this.title = itemInfo.title
            this.desc = itemInfo.desc
            this.newPrice = itemInfo.price
            this.oldPrice = itemInfo.oldPrice
            this.discount = itemInfo.discountDesc
            this.columns = columns
            this.services = services
            this.realPrice = itemInfo.lowNowPrice
          }
        }
        
        // 定义商家类
        export class Shop {
          constructor (shopInfo) {
            this.logo = shopInfo.shopLogo
            this.name = shopInfo.name
            this.fans = shopInfo.cFans
            this.sells = shopInfo.cSells
            this.score = shopInfo.score
            this.goodsCount = shopInfo.cGoods
          }
        }
        
        // 定义参数类
        export class GoodsParam {
          constructor (info, rule) {
            this.image = info.image ? info.image : ''
            this.info = info.set
            this.sizes = rule.tables
          }
        }
        
  • 商品分类视图组件的封装

    • 相对于其他视图来说较为简单,一点难度在于网络请求的封装
  • 个人信息视图组件的封装

    • 开发中~~~~