重构商城App项目——知识总结

652 阅读7分钟

参考文档:mint UIswiper


  1. index.html 标签解释
  • <link rel="dns-prefetch" href="#"> DNS预解析,可以减少图片的解析时间。
  1. Vue 相关知识
  • vue实例挂载点,不能是 body 或 html , 所以要加一层容器,包裹想要挂载的地方。
  • 单vue文件,template 是必需的而且只能有一个根节点,style 可以有多个。
  • Vue组件库:自行查找
Mint UI 对比 Element UI

首页

  1. Mint UI :基于 Vue.js 的移动端组件库
- 1. npm安装
    $ npm i mint-ui -S
    
- 2. 引入 Mint UI
    - 1. 完整引入
    - 2. 按需引入
         1.需要安装babel-plugin-component:
         $ npm install babel-plugin-component -D
         2.然后,将 .babelrc 修改为:
             {
              "presets": [
                ["es2015", { "modules": false }]
              ],
              "plugins": [
                  // 主要是这部分 , 实际使用时,大括号外的中括号需去掉(代码复制于官网)
                  ["component", [  
                    {
                      "libraryName": "mint-ui",
                      "style": true
                    }
                  ]]
                  // 到这部分
              ]
            }
            
- 3. 选择想要引入的组件按指令操作即可。
  • 触底加载更多数据———Infinite scroll:无限滚动指令
- 1. 引入
    import { InfiniteScroll } from 'mint-ui';
    Vue.use(InfiniteScroll);
    
- 2. 例子
    为 HTML 元素添加 v-infinite-scroll 指令即可使用无限滚动。滚动该元素,
    当其底部与被滚动元素底部的距离小于给定的阈值(通过 infinite-scroll-distance 设置)时,
    绑定到 v-infinite-scroll 指令的方法就会被触发。
    
    <ul
      v-infinite-scroll="getLists"        // 绑定到 v-infinite-scroll 指令的方法就会被触发
      infinite-scroll-disabled="loading"  // 若为真,则无限滚动不会被触发       
      infinite-scroll-distance="10">      // 触发加载方法的滚动距离阈值(像素)   
      <li v-for="item in list">{{ item }}</li>
    </ul>
    
- 3. bug: 触发绑定的方法期间,若再次触发,则仍会触发该方法,这是不合理的。
    设置loading值:在触发方法时先设置loading=true ,方法完成后设置loading=false
    
- 4. bug: 每次触发方法只刷新数据,原数据被覆盖,这不符合商品列表的期望。
    得到当前的商品列表(curLists)时,判断商品列表(lists)是否为空:
        空则直接赋值 this.lists = curLists
        非空则使用数组拼接方法连接数据 this.lists = this.lists.concat(curLists) 
    
  1. bottom-nav
- 1. 将 bottom-nav 单独拿出来,放在新建的 Foot.vue 中, 并且抽出对应的css 放入style中。
- 2. 点击底部按钮时,要完成两个任务
    - 1. 点击按钮,切换页面,切换样式
        - 1. 将四个按钮使用v-for渲染,let navConfig = [],存放四个按钮的 name,href,icon
        - 2. 使用 index === curIndex 法渲染 active 效果。
        发现:切换页面后,渲染的效果失效
        方法: 切换页面时传递index参数: location.href = `${list.href}?index=${index}`
              渲染界面时,解析href得到index: 
                let {index} = qs.parse(location.search.substr(1))
                curIndex: parseInt(index) || 0 
     
     需要引入 qs ,解析 location 。
  1. swiper
将 swiper-container 拿出来,放在新建的 Swipe.vue 中

使用swiper组件:
- 1. 下载并安装swiper
     $ npm install swiper
     
- 2. 分析:除首页需要轮播,商品详情页需要轮播,所以把轮播组件单独拿出来,
     使用的时候只需要传递不同的数据(参数)即可。
     
- 3. 在 index.html 中引入 Swipe
    - 1. 在 api.js 中加入 轮播图的路径:  banner: '/index/banner'
    - 2. 在 index.js 的 methods 中 写 getBanner 方法,并且放入 created 中
    - 3. 在 index.js 中引入 Swipe.vue ,并放入 components 中
    - 4. 在 index.html 中对应位置写<Swipe></Swipe>
    
- 4. 把数据传递给给组件,让组件进行渲染 ———— props(Vue-组件-prop 查看 props的数组形式、对象形式)
    - 1. 在 Swipe.vue 中 写props对象形式(对象形式能进行 prop验证 )
        对象形式:
          props:{
              lists:{
                type: 指定输出类型
                required: true时,必须符合 type 的类型  
              }
          }
    - 2. 当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
         注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 
         (如 data、computed 等) 在 default 或 validator 函数中是不可用的。
         
- 5. 使用 Swiper 组件时,要遵守人家给出的页面格式:
        <!-- Slider main container 滑块主容器 -->
        <div class="swiper-container">
            <!-- Additional required wrapper 附加所需包装器 -->
            <div class="swiper-wrapper">
                <!-- Slides 幻灯片 -->
                <div class="swiper-slide">Slide 1</div>
                <div class="swiper-slide">Slide 2</div>
                <div class="swiper-slide">Slide 3</div>
                ...
            </div>
            <!-- If we need pagination 如果我们需要分页 -->
            <div class="swiper-pagination"></div>
        
            <!-- If we need navigation buttons 如果我们需要导航按钮 -->
            <div class="swiper-button-prev"></div>
            <div class="swiper-button-next"></div>
        
            <!-- If we need scrollbar 如果我们需要滚动条 -->
            <div class="swiper-scrollbar"></div>
        </div>
     所以按照此格式,在 index.html-Swpie 中补充 class ,加入分页器
     
- 6. v-for 列表渲染 swiper-slide , 并且动态绑定url、img

- 7. swiper是对dom节点进行操作的,dom节点什么时候生成?
     生命周期:mounted
     - 1. index.html 中
          <Swipe :lists="bannerLists" v-if="bannerLists"></Swipe>
          只有获得了数据,才会渲染
     - 2. Swipe.vue 中 (此时不需要限制 lists 的类型)
          对数据进行监听
          created() {
            // console.log('created: ',document.querySelectorAll(".swiper-slide"));
          },
          mounted() {
            // console.log('mounted: ',document.querySelectorAll(".swiper-slide"));
          },
          watch: {
            lists(value, oldValue) {
              console.log('value, oldValue: ',value, oldValue);
              console.log('before nextTick: ',document.querySelectorAll(".swiper-slide"));
              this.$nextTick(() => {
                console.log('after nextTick: ',document.querySelectorAll(".swiper-slide"));
              });
            }
          }
          结果:
            created:  NodeList []
            mounted:  NodeList []
            value, oldValue:  (3) [{…}, {…}, {…}, __ob__: Observer] null
            before nextTick:  NodeList []
            after nextTick:  
            NodeList(3) [div.swp-page.swiper-slide, div.swp-page.swiper-slide, div.swp-page.swiper-slide]
            
    注意:项目中选择了 1 方法,以下代码都是按照 1 方法进行。
    
- 8. 引入 Swiper ,并引入 Swiper 的样式:
        import Swiper from 'swiper'
        import 'swiper/dist/css/swiper.css'
        
- 9. 配置Swiper(参考官方文档)
     在mounted中:
            var mySwiper = new Swiper(".swiper-container", {
              direction: "horizontal", // 水平方向轮播
              loop: true,              // 设置为true以启用连续循环模式
              pagination: {            // 分页器
                el: ".swiper-pagination"
              },
              autoplay: {              // 自动轮播,延迟5s
                delay: 5000
              }
            });

分类页

  1. 基础处理
- 1. 将 category.html category.css 放入新建的 pages/category 文件夹,
     并创建 category.js ,引入响应的css,引入Vue、axios、Foot、url 。
     并将 category.html 中Foot对应的部分删除,切换为   <Foot></Foot>
     用div(id=app) 包裹整个页面,用来挂载vue实例
     
- 2. 找到右边商品列表的容器:class="main-content",在对应的css上写   overflow-y: scroll;
     overflow:定义当一个元素的内容太大而无法适应 块级格式化上下文 时候该做什么
               是 overflow-x、overflow-y 的简写
            属性:
             - 1. visible:默认值。内容不会被修剪,可以呈现在元素框之外。
             - 2. hidden:如果需要,内容将被剪裁以适合填充框。 不提供滚动条。
             - 3. scroll:如果需要,内容将被剪裁以适合填充框,浏览器一直显示滚动条
             - 4. auto:取决于用户代理。如果内容适合填充框内部,则它看起来与可见内容相同,
                        但仍会建立新的块格式化上下文。 如果内容溢出,桌面浏览器会提供滚动条。
            注意:
             - 1. 除visible外的值均会创建一个新的快格式化上下文。
             - 2. 为使 overflow 有效果,块级容器必须有一个指定的高度(height或者max-height)
                  或者将white-space设置为nowrap。
             - 3. 设置一个轴为visible(默认值),同时设置另一个轴为不同的值,会导致设置visible
                  的轴的行为会变成auto。
             - 4. 即使将 overflow 设置为 hidden ,也可以使用JavaScript Element.scrollTop
                  属性来滚动HTML元素。
  1. 页面分析
- 1. 侧边的一级分类的数据也是获得的,
    data-cid="xx" 是什么意思?
  1. 获得 一级分类 的数据并渲染
- 1. 在 api.js 中 url写入:topList: '/category/topList'
- 2. 在 category.js 中 创建vue实例,并绑定在 div(app) 上,
     data 中声明    topLists: null
- 3. methods 中写 getTopList(){axios.get(url.topList).then(res => {this.topLists = res.data.lists})}
     并在 created 中 调用该方法 created() { this.getTopList() }
- 4. 在 category.html 中
     找到一级分类,在 li 上使用v-for进行列表渲染 v-for="(list,index) in topLists"
     
     此处有两个问题:
     1. 点击不同的li,渲染不同的标签(实际上只有综合排行为一种,剩下的分类为一种)
     - 1. category.html 中
          在 <li> 上绑定事件    @click="getSubList(index,list.id)"
          在综合排行对应的div上写 v-show="topIndex===0" (后更改为v-if)
          在其余分类对应的div上写 v-show="topIndex>0"  (后更改为v-if)
     - 2. category.js 中
          data:{ topIndex: 0 // 此处按照下标进行区分,综合排行为0,其余均大于0 }
          methods: {  getSubList(index,id) { this.topIndex = index}  }
     2. 点击不同的li,切换 class"active"(焦点状态切换问题)
     - 1. 在<li>上添加  :class="{active:index===topIndex}"
          由 getSubList() 方法可知,点击哪个li就会使得topIndex等于被点击li的index
          当点击 li 时,就会使得条件成立,渲染clas"active"
          此时其余的未被点击的 li 的index是不等于topIndex的
          所以就实现了切换 active 的需求。
  1. 获得 二级分类(综合排行、普通分类) 的数据并渲染
- 1. 在 api.js 中 url写入:  
        subList:'/category/subList',
        rank:'/category/rank',
- 2. 在 category.js 中 创建vue实例,并绑定在 div(app) 上,
     data 中声明    topLists: null
- 3. methods 中写 getTopList(){axios.get(url.topList).then(res => {this.topLists = res.data.lists})}
     并在 created 中 调用该方法 created() { this.getTopList() }
- 4. 在 category.html 中
     找到对应的 li 使用 v-for 进行渲染,并对数据进行替换
- 5. 问题:subData、rankData 初始值为null,再页面刚打开时就渲染会报错。
     办法:在对应的 ul 上写 v-if="subData" 或者 v-if="rankData"
           当获取数据后,才渲染。
- 6. 将价格变为带两位小数的浮点数:
     使用filter,结合toFixed()方法即可。
  1. 问题补充:null 和 undefined


列表页

  1. sku
  2. 为什么data要return数据:在单vue页面下,多个组件可能会共享数据,为了保持数据的独有性,就把数据return出去。
  3. qs: querything 是一个增加了一些安全性的查询字符串解析和序列化字符串的库。
qs.parse()
  1. 点击热门品牌、热门分类下的 item ,会跳转到 search.html ,且传递点击 tiem 的 id 和 name
location.href = `search.html?keyword=${list.name}&cate_id=${list.id}`
  1. search 中
search.js 中
- 1. getSearchList(){} 发请求获取searchLIst
- 2. let { keyword, id } = qs.parse(location.search.substr(1)) 接收 keyword,id

search.html 中
- 1. input中接收keyword:`:value="keyword"`
- 2. 对应 li 上v-for 渲染数据。
  1. 发现:foot组件复用,formatePrice 方法复用,所以引入 mixin.js
- 1. src/modules/js/mixin.js 中
    import Foot from '@/components/Foot.vue'
    let mixin = {
      filters: {
        formatePrice(value) {
          return value.toFixed(2)
        }
      },
      components: {
        Foot
      }
    }
    export default mixin
    
    将引入 foot 、formatePrice 方法均放入 mixin.js 中
- 2. 在需要引入 mixin.js 的文件中
     import mixin from 'js/mixin.js'
    new Vue({
        ···
        mixins:[mixin]
        ···
    })
  1. 回到顶部
使用第三方库:velocity

过渡

  1. 过渡的概念
  2. 在哪些场景使用过渡
  3. 怎么用
  4. 涉及到的知识点
  1. 组件的封装
  2. slot--组件
  3. 组件的通讯
  1. 父子
  2. 兄弟
  3. vuex
  4. slot
  1. fullpage
  1. 静态数据:mounted
  2. 异步数据:this.$nextTick

详情页

  1. 入口、数据获取和渲染
  2. 商品详情和本店成交
  3. 选择规格弹框:过渡效果、数据增减
  4. 加入购物车:购物车按钮显示、信息提示

知识点:

  1. v-cloak
  2. v-html
  3. 过渡效果