仿蘑菇街移动端练手项目------第一阶段心得总结
技术栈
- 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…
项目目录结构
原来是这样噢
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的基本使用和配置(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 } }
-
-
-
商品分类视图组件的封装
- 相对于其他视图来说较为简单,一点难度在于网络请求的封装
-
个人信息视图组件的封装
- 开发中~~~~