Vue项目—supermall

255 阅读9分钟

一、 创建项目

  • VueCLI 2: vue init webpack mall('项目名')
  • VueCLI 3+:vue create mall('项目名')

二、 项目文件夹划分

  • 主要划分src文件夹下面的内容

    1. asset(资源) -- css + img

    css用于存放共有的css文件; img用于存放一些共有的图片。

    2. common

    common用于存放一些公共的js文件,如抽取的功能函数。

    3. components -- common + content

    common文件夹存放可以在任何项目中都可能会用到的公用组件; content文件夹存放只在当前项目中会用到的公用组件。

    4. network

    network用于存放网络配置相关。

    5. router

    router用于存放vue-router相关。

    6. store

    store用于存放vuex状态管理相关。

    7. views

    views用于存放一些大的视图(可通过tabbar直接进行切换的主页面),在其中再进行各小部分细分。

三、 引入基础样式文件

  • 引入normalize.css(可在GitHub上找到)及base.css对样式进行初始化(在base.css中使用@import "./normalize.css"导入normalize.css,在App.vue中使用@import "assets/css/base.css"导入base.css)。

四、 给某些常用文件夹配置别名

  • 创建vue.config.js在其中完成配置, 配置完成之后可不考虑路径问题, 直接用别名进行引入。(注:在DOM中使用别名前面需要加 ‘~’)
// 配置别名
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        'assets': '@/assets',
        'common': '@/common',
        'components': '@/components',
        'network': '@/network',
        'views': '@/views'
      }
    }
  }
}

五、 创建.editorconfig文件实现对代码风格的一些控制

<!--.editorconfig-->
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

六、 tabbar实现项目模块化划分

  • 复制原来写好的tabbar模块(tabbar文件夹下为公用部分,maintabbar文件夹下为该项目独用部分),修改路径。
  • 路由相关

    1. 路由安装

npm install vue-router --save

2. 路由创建

router文件夹下index.js

// 1. 导入路由对象,并且调用Vue.use(vueRouter)安装路由功能
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 路由懒加载
const Home = () =>
  import ('views/home/Home')
const Category = () =>
  import ('views/category/Category')
const Cart = () =>
  import ('views/cart/Cart')
const Profile = () =>
  import ('views/profile/Profile')

// 2. 创建路由实例(VueRouter),并且传入路由映射配置(routes)
const routes = [{
    path: '',
    redirect: '/home'
  },
  {
    path: '/home',
    component: Home
  },
  {
    path: '/category',
    component: Category
  },
  {
    path: '/cart',
    component: Cart
  },
  {
    path: '/profile',
    component: Profile
  }
]
const router = new VueRouter({
  routes,
  mode: 'history'
})

// 3. 导出router
export default router

3. 路由使用

main.js中导入router,并注册router。

七、 分模块开发

1. 网络模块获取接口数据(axios)

主要原理
axios相关
Promise相关
Vue生命周期相关

1.1 安装axios

npm install axios --save

1.2 编写基础请求文件 (request.js)

import axios from 'axios'

export function request(config) {
  // 1. 创建axios实例
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })

  // 2. axios的拦截器
  // 2.1 请求拦截
  instance.interceptors.request.use(config => {
      return config
    }, err => {

    })
    // 2.2 响应拦截
  instance.interceptors.response.use(res => {
      return res.data
    }, err => {
      console.log(err);
    })
    // 3. 创建真正的网络请求
  return instance(config)
}

1.3 编写各页面各部分数据对应的请求 (例:home.js)

import { request } from './request'

export function getHomeMultidata() {
  return request({
    url: '/home/multidata'
  })
}

1.4 在Home.vue中获取数据

import {getHomeMultidata} from 'network/home'

data() {
    return {
      banners : [],
      recommend : []
    }
  },
  created() {
   getHomeMultidata().then(res => {
    //  console.log(res);
    this.banners = res.data.banner.list
    this.recommend = res.data.recommend.list
   })
  }

2. 首页部分

2.1 navbar

由于navbar组件需要在多个地方用到,首先封装一个有三个具名插槽的NavBar.vue,该在Home.vue中导入并注册。注意:创建插槽时需要使用div包起来。  

2.2 轮播图

首先封装一个公共组件(Swiper.vue),然后封装轮播图中放图片和小圆点的公共组件(SwiperItem.vue),再创建index.js对Swiper和SwiperItem统一导出,最后在home文件夹下创建childComps文件夹(用于存放home组件中引用的子组件),在该文件夹下创建HomeSwiper.vue对Home.vue中swiper部分进行抽取,在抽取的组件中用props获得父组件(Home.vue)中轮播图相关数据,v-for循环遍历将数据插入到SwiperItem中,v-bind绑定链接的href和图片的src,在Home.vue中导入注册使用该子组件。

2.3 recommend推荐模块

首先在childComps中创建RecommendView.vue,通过props获得父组件(Home.vue)中recommend相关数据,v-for循环遍历将数据插入到div容器中,v-bind绑定链接的href和图片的src,在Home.vue中导入注册使用该子组件。

2.4 商品展示模块

  • TabControl.vue选项卡模块
    (1). 组件基本结构搭建
    TabControl组件在多个地方用到,故将其封装成与当前项目业务相关的公共组件,结构是一个div中包含三个span,且这三个span展示的标题由父组件传入(给子组件添加props传入类型和默认值),通过v-for循环遍历以及mustache语法插入并展示。
    (2). 组件实现功能
    实现点击后标题变色并添加下边框,给标题添加@click点击事件itemClick,传入index参数,默认展示index为0的选项卡,因此设置默认的currentIndex为0,通过index获取当前被点击的标题,把获得到的index赋值给currentIndex,如果当前点击的选项卡的index===currentIndex,就给它动态绑定一个类,该类中实现变色添加下边框。
  • 首页商品数据请求
    (1). 存储商品数据的数据结构设计
    goods为一个对象,包含三个对象pop&new&sell,这三个对象中包含page&list,page用于存储数据的页数,list是一个数组用于存储数据。
    (2). 获取首页数据
    为了更好的用户体验,首先需要将每个选项下的第一组list数据请求下来,在首页网络请求的home.js中封装请首页求数据的函数getHomeGoods,该函数需要传入两个参数typelist,type用于确定哪个选项卡的数据,list是请求到的数据,在Home.vue中导入home.js中的getHomeGoods,并在home.vue网络请求模块封装getHomeGoods函数用于请求数据,传入一个参数type,用于确定请求的数据类型,在该函数中定义page变量用于存放数据的页数,并调用home.js中的getHomeGoods函数,将page和type作为参数,通过Promise得到res,打印res的结构,从中取出需要用到的部分,即res.data,list,使用 ...拓展运算符将res.data.list数组的值push到原先设计好的goods[type].list数组中,push完成后page+1,完成封装后,在vue的created生命周期函数调用三次该函数,分别传入pop、new、sell三个参数,获取到三个选项卡的第一页数据,通过v-bind将数据从父组件Home.vue传递到子组件GoodsList.vue中。
  • GoodsList.vue具体展示模块
    分析页面结构,一个大的GoodsList组件中包含许多个小的GoodsListItem组件,在GoodsList中通过props拿到首页获取到的list数据,v-bind将数据动态绑定给一个Object对象,通过v-for循环遍历生成一个个小的GoodsListItem组件的内容,在小组件中展示具体的内容。实现上拉加载更多
  • BackTop回到顶部模块

2.5 首页bug解决

首页bug

3. 详情页

3.1 详情页数据获取

(1)全部数据获取
iid为参数获取到每个商品不同的数据,首先在detail详情页主要视图中获取每个商品不同的iid,点击每个商品时通过this.router.push方法导航到不同的URL并传入iid,在detail.vue通过this.router.push**方法导航到不同的URL并传入iid,在detail.vue通过**this.route.params拿到这个参数,并保存这个参数,在detail.vue的creat生命周期函数中调用请求数据需要的参数,传入iid,拿到详情页全部的数据。
(2)具体各部分数据获取
在获取完全部数据的函数中分别获取其他各部分的数据,由于原始数据复杂难以操作,为了灵活使用各部分数据,在网络请求中声明有复杂数据结构的函数,在函数内部根据获取的总的数据结构对数据进行整理,调用各个函数的时候传入参数,并保存各个部分的数据。

3.2 分模块开发

(1)DetailNavBar导航栏的重新封装
在childComps中创建DetailNavBar.vue组件,复用NavBar.vue组件,在center插槽中循环遍历传入不同的title,后对其进行样式控制,点击之后实现变色。
(2)DetailSwiper轮播图的重新封装
在childComps中创建DetailSwiper.vue组件,通过props拿到轮播图页面数据,循环遍历生成多个SwiperItem,在其中展示图片。
(3)DetailBaseInfo商品信息模块
在childComps中创建DetailBaseInfo.vue组件,通过props拿到商品信息的数据,根据图片编写HTML对其进行展示,并控制样式。
(4)DetailShopInfo商家详情信息模块
同商品信息模块,增加了filter函数对总销量进行控制,超出10000的写成几.几万(filter)。
(5)DetailGoodsInfo商品详情模块
同商品信息模块,增加了


(6)DetailParamInfo商品参数信息模块
同商品信息模块。
(7)DetailCommentInfo商品评论模块
同商品信息模块,增加了时间格式化函数,对用户评论的时间格式化处理。
(8)GoodsList商品展示模块
复用GoodsList商品展示模块,传入需要展示的商品数据。
(9)DetailBottomBar底部工具栏模块
封装独立组件,使其固定展示在页面的最下方。

3.3 页面主要功能逻辑的实现

(1)顶部导航栏点击后跳转至页面指定位置
给DetailNavBar添加click点击事件,通过 $emit 自定义事件发送到父组件中,父组件接收到子组件的点击事件并接收到接收点击的标题的index,详情页面图片加载完成之后对每个需要跳转的组件通过 $refs 对其进行访问,拿到他们的offsetTop值(组件无法直接获取它的offsetTop,需要通过组件的根元素 el获取),并将其保存到themeTopY数组中,在每一次详情页完成一次更新后对其进行调用,给标题绑定click事件,点击后通过el** 获取),并将其保存到themeTopY数组中,在每一次详情页完成一次更新后对其进行调用,给标题绑定click事件,点击后通过refs拿到scroll组件调用其中封装好的scrollTo方法,跳转至刚保存的themeTopY[index]位置。
(2)滑动页面上方展示对应主题
在Scroll组件中封装监听滚动位置的函数,通过 $emit 发送自定义事件及滚动位置position,在Detail的Scroll组件中监听该事件,将当前position中的Y值保存为positionY,通过for循环遍历及if条件判断,当前位置的positionY大于第i个&&小于第i+1个组件的offsetTop值时,应当在第i个组件的区域内,将i赋值给当前的currentIndex,再把当前组件中的currentIndex赋值给DetailNavBar的currentIndex。
(3)底部加入购物车
加入购物车首先需要有购物车页面展示的数据,在监听到加入购物车被点击之后,在Detail页面对数据进行保存,之后在加入购物车时将数据动态的保存到购物车组件中,此部分数据需要动态保存及动态更新,所以需要保存到
vuex**中,加入购物车与当前商品数量+1都需要对其进行状态追踪。


4. 购物车页面