基于VUE2.0的高仿饿了么分析与总结

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

        首先,慕课网提供的视频是基于vue1.0的规范写的,因此有一些地方在vue2.0下不能正常运行。虽然课程补充文件也提供了vue2.0的代码,但多多少少也有一些问题。参考他人写的代码以及官方文档,修改了部分内容,整个项目能够流畅运行,不会报错。

        项目请移步我的github地址:https://github.com/gqbwoai2016/-VUE2.0-APP-。里面内容还不是很多,以后会继续丰富的。

-------------------------------------------------------------------------------------------------------------------------------------------------

废话就这么多,开始实质的内容吧:

        涉及的工作有:由商家模块入手,进行需求分析,利用脚手架工具搭建,mock数据,架构设计,代码实现,自测以及编译打包。本项目注重代码规范:架构设计,组建抽象,模块拆分,代码风格统一,JS变量命名规范及CSS代码规范。

        所涉及的技术有:vue-cli脚手架工具;vue-resource与后端数据交互(类似AJAX);vue-router插件管理路由;第三方库better-csroll;最大程度组件化(优点:可维护性和复用性);localstorage;flex弹性布局;

        实现的功能

•    Goods、Ratings、Seller组件视图均可上下滚动
•    商品页 点击左侧menu,右侧list对应跳转到相应位置
•    点击list查看商品详情页,父子组件的通信
•    评论内容够可以筛选查看
•    购物车组件,包括添加删除商品及动效,购物控件与购物车组件之间非父子组件通信,点击购物车图标,展示选择的商品列表
•    商家实景图片可以左右滑动 
•    loaclStorage缓存商家信息(id、name)

        0、用vue-cli脚手架工具搭建项目结构,有以下结构

项目名称
 ->build          ------------------------------------------  webpack配置相关文件
 ->config         ------------------------------------------  webpack配置相关文件      
 ->node_modules   ------------------------------------------  依赖代码库
 ->src            ------------------------------------------  存放源码
   ->common       ---- 通用的css和fonts
   ->components   ---- Vue 组件
   ->router       ---- vue-router相关配置(linkActiveClass,routes注册组件路由)
   ->build        ---- webpack 的打包编译配置文件
   ->config       ---- 一些配置项,比如我们服务器访问的端口配置等
   ->dist         ---- 项目经过 build 之后才会生成
   ->prod.server.js----模拟的服务器配置,用来运行dist里面的文件,在config/index.js中,build对象中
                        添加一条端口设置port:9000,
   ->App.vue      ---- 根组件,所有的子组件都将在这里被引用
   ->index.html   ---- 整个项目的入口文件,将会引用我们的根组件 App.vue
   ->main.js      ---- 入口文件的 js 逻辑,在 webpack 打包之后将被注入到 index.html 中
 ->static         ------------------------------------------  存放第三方静态资源
 ->.babelrc.JSON  ------------------------------------------  babe的配制,用于从es6编译至es5
 ->.editorconfig  ------------------------------------------  编译器配置
 ->.eslintignore  ------------------------------------------  忽略语法检查的目录文件
 ->.eslintrc.js   ------------------------------------------  eslint的配置
 ->.gitignore     ------------------------------------------  git忽略的目录或文件
 ->index.html     ------------------------------------------  入口文件,项目编译过程中会自动插入其中
 ->package.json   ------------------------------------------  配置文件,描述一个项目
 ->README.md      ------------------------------------------  项目描述文件

        所有项目文件放在src下,main.js为入口文件,APP.vue为整个页面的vue,components存放组建文件,里面有许多子目录,子目录中存放.vue文件及图片等资源(满足组件化开发的就近维护)。common包含公共模块资源(js,scss,fonts等)。        

  • Hot-reload Vue的热更新,修改代码之后无需手动刷新网页,对前端开发来说非常方便
  • PostCss,再也不用去管兼容性的问题了,只针对chrome这样的现代浏览器写css代码,会自动编译生成兼容多款浏览器的css代码
  • ESlint,统一代码风格,规避低级错误(在eslintrc.js文件里面:rules是自定义的检查规则,可以覆盖默认的检查规则,例如要加分号,函数要加空格,这个跟代码风格有关)。在.eslintrc.js里的rules中写自定义规则,如'space-before-function-paren': 0,函数定义是括号前空格取消。
  • Bable,ES2015出来已经有一段时间了,但是不少浏览器还没有兼容ES6,有了bable,放心使用ES6语法,它会自动转义成ES5语法
  • SCSS,一款 CSS预处理器,编译后成正常的CSS文件。为CSS增加一些编程的特性

       1、 数据mock

            mock就是做假数据,这样可以便于前后端分离开发,前端不需要等后端做好数据来开发或者测试验证

            假数据data.json.实现:sell(项目总文件)->插入data.json,然后在build->webpack.dev.conf.js中写数据接口,然后写数据的路由。

        坑1,最新版的vue中dev-server.js被替换成了webpack.dev.conf.js,修改时注意

        2、reset

            sell->static->css->reset.css,写好后给index.html用link标签引用这个文件

        3、meta

            对其设置viewport以规范显示大小,缩放等移动端视口初始化。

        4、header组件开发

            a)使用vue-router实现点击切换;在这里,当前模块样式在vue-router中有个默认属性linkActiveClass,在main.js对其配置后,在APP.vue中通过创建点击部分以及创建展示部分;

            vue-router详解:

                路由,其实就是指向的意思。我们页面中所有内容都是组件化的,我们只要把路径和组件对应起来就可以了,然后在页面中把组件渲染出来。    

                页面实现:定义了两个标签来对应点击和显示部分。 就是定义页面中点击的部分, 定义显示部分,就是点击后,区配的内容显示在什么地方。所以  还有一个非常重要的属性 to,定义点击之后,要到哪里去, 如:Home   

                js中配置路由:首先定义route,由path,component组成,前者指路径,后者指组件,如下所示,最后创建router管理路由。配置完成后,把router 实例注入到 vue 根实例中,就可以使用路由了

const routes = [
  { path: '/home', component: Home },
  { path: '/about', component: About }
]
//管理路由
const router = new VueRouter({
      routes // routes: routes 的简写
})
//配置完成,注入到实例中
const app = new Vue({
  router
}).$mount('#app')//$mount为手动挂载
//上面这个写法也可以改为
new Vue({
    el:"#box",
    router
});

                注意:当首次进入页面的时候,页面中并没有显示任何内容。这是因为首次进入页面时,它的路径是 '/',我们并没有给这个路径做相应的配置。在这里使用重定向解决问题。

const routes = [
    {
        path:"/home",
        component: home
    },
    {
        path: "/about",
        component: about
    },
    // 重定向
    {
        path: '/', 
        redirect: '/home' 
    }
]

            b)1像素实现:在APP端由于dpr不同,展示会有问题,因此添加minxin.scss设置通用样式后再通过base.scss使用@media 媒体查询来分别设置不同dpr的scale控制样式;

             window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。公式表示就是:window.devicePixelRatio = 物理像素 / dips           

            非视网膜屏幕的iphone上等于1,在视网膜屏幕的iphone上,屏幕物理像素640像素,独立像素还是320像素,因此等于2。

            2x和3x图是为了适应不同dpr比例的,不同比例的显示是不一样的.2x就是普通的dpr为1的屏幕使用的;  对于高清屏幕就是用3x,dpr为2或者以上;  2x和3x就是尺寸的大小,2x的图片比3x的小

           c)满减图标在export default中create()内使用

classMap=['discount'...]

创建,在标签中通过

:class="classMap[seller.supports[0].type]"

引用。

            d)背景模糊:整个header组件中有模糊背景图,可通过创建一个div然后绝对定位至相关位置,再用z-index=-1设置后,使用

filter:blur(15px)增加模糊效果。

           e)css sticky footers模块:简而言之就是底部有一个固定图标,只有移动至底部区域才展示,否则不显示的一种布局。

                    父级 position:fixed,内容设 为padding-bottom:64px,页脚相对定位,margin-top:-64px,clear:both
为了保证兼容性,父级要清除浮动           

        坑2:新旧版vue-router不同,旧版支持router.map(),新版则使用const router=new VueRouter()直接在里面写即可   

            g)flex布局:

                    意为"弹性布局",用来为盒状模型提供最大的灵活性。设为Flex布局以后,子元素的floatclearvertical-align属性将失效。以下六个属性设置在容器上:

                    flex-direction  容器内项目的排列方向(默认横向排列)。可选值为row(默认)沿水平主轴由左向右排列、row-reverse沿水平主轴由右向左排列、column沿垂直主轴右上到下和column-reverse

                    flex-wrap  换行方式。nowrap(默认)不换行、wrap换行(第一行在上方)和wrap-reverse

                    flex-flow  以上两个属性的简写方式 .box {  flex-flow:  || ;}将上述两种方法的值用||连接即可

                    justify-content  主轴上的对齐方式。主轴究竟是哪个轴要看属性flex-direction的设置了flex-start:在主轴上由左或者上开始排列;flex-end:在主轴上由右或者下开始排列;center:在主轴上居中排列;space-between:在主轴上左右两端或者上下两端开始排列;space-around:每个项目两侧的间隔相等。

                    align-items  交叉轴上如何对齐(纵轴对齐方式)flex-start顶对齐| flex-end底对齐 | center居中 | baseline文字基准线 | stretch撑开整个盒子

                    align-content  定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

            设置在子元素的属性也有六个:

                    order:项目排列顺序,数值越小排名靠前,默认为0;

                    flex-grow:项目放大比例,默认0;

                    flex-shrink:缩小比例,默认1;

                    flex-basis:计算主轴是否有多余空间,默认auto,项目本来大小;

                    flex:是上面三个简写,默认0 1 auto;

                    align-self:允许单个项目有与其他项目不一样的对齐方式。

            f)自适应布局

                    左侧宽度固定,右侧宽度自适应

// 左侧固定width:80px,右侧自适应
parent:
    display:flex;
child-left:
    flex:0 0 80px
child-right:
    flex:1

        5、goods模块

            a)采用better-scroll实现滚动,在package.json表明版本,使用npm安装。BScroll接受两个参数,第一个是DOM对象,第二个是方式,在method中写方法,需要设置 click:true,否则移动端滑动无效。

            注意:vue提供一种方法获取DOM,在需要获取地方添加ref="**",然后在js中通过this.$ref.**来引用;

                      DOM真正映射实在nextTick后,因此一些计算属性应该写在里面,否则在页面中无响应;

        6、seller组件

                a)商家实景图片横向滚动:

                    解决方案:每个 li 要 display:inline-block,因为width不会自动撑开父级ul,所以需要将计算后的宽度赋值给ul的width,(每一张图片的width+margin)*图片数量-一个margin,因为最后一张图片没有margin,同时new BScroll里面要设置scrollX: true, eventPassthrough: 'vertical', // 滚动方向横向

                b)打开seller页面,无法滚动

                    问题分析:出现这种现象是因为better-scroll插件是严格基于DOM的,数据是采用异步传输的,页面刚打开,DOM并没有被渲染,所以,要确保DOM渲染了,才能使用 better-scroll;解决方案:用到mounted钩子函数,同时必须搭配this.$nextTick()

                c)刷新后,无法滚动

                    问题分析:出现这种情况是因为mounted函数在整个生命周期中只会只行一次;解决方案:使用watch方法监控数据变化,并执行滚动函数 this._initScroll();this._initPicScroll();

                d)缓存数据

                    使用window.localstorage保存舍设置缓存信息,封装在store.js中

                e)axios

                    在vue1.x的时候,vue的官方推荐HTTP请求工具是vue-resource,但是在vue2.0的时候将推荐工具改成了axios。如果想像以前使用 vue-resource 那样 this.$http.get 调用,要这样定义:Vue.prototype.$http=axios;

                    通过 this.$http.get 来定义通过vue实例来发送get请求,然后通过then后面的回调函数将请求成功的数据接收,通过状态码来判断是否成功以及复制给vue的数据对象。由于这里是用的mock数据(模拟后台数据),所以用的模拟状态码。

const ERR_OK = 0;//表示没有错误信息,即获取数据成功
this.$http.get('/api/seller').then((response) => {
  response = response.data;
  if (response.errno === ERR_OK) {
    this.seller = Object.assign({}, this.seller, response.data);
  }
});

                vue-resource详解:

                    vue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应。也就是说,$.ajax能做的事情,vue-resource插件一样也能做到,而且vue-resource的API更为简洁。

                优点:体积小;支持主流浏览器;支持PromiseAPI和URI Templates;支持拦截器。

                使用:

                    首先引入vue-resourec;然后发送请求即可

import VueResource from 'vue-resource';
Vue.use(VueResource);

this.$http.get('/someUrl',jsonData).then(function(response){  //jsonData是传给后端的数据
    // 响应成功回调
}, function(response){
    // 响应错误回调
});

                   下面给个实例,从a.txt取数据




    
    
    
    
    

 
    

                    最新版Vue推荐使用axio,两个功能类似,首先也要安装然后引入,最后再使用:(注:他的注册不能使用Vue.use()方法)

import axios from "axios";
//注册
Vue.prototype.$axios = axios;
//使用axios
created:function(){
  this.$axios.get("/seller",{"id":123}).then(res=>{
   console.log(res.data);
 });
}

                f)组件间通讯               

                父传子: props 

// 父组件


// 子组件 header.vue
props: {
  seller: {
    type: Object
  }
}

                子传父: $emit       如果是子组件想传递数据给父组件,需要派发自定义事件,使用 $emit 派发,父组件使用v-on接收监控(v-on可以简写成@)

// 子组件 RatingSelect.vue,派发自定义事件isContent,将this.onlyContent数据传给父级

this.$emit('isContent', this.onlyContent);
this.$emit('selRatings', this.selectType);

// 父组件 foodInfo.vue 在子组件的模板标签里,使用v-on监控isContent传过来的数据

                非父子组件之间通信: 1. 大型项目可以用 Vue官方推荐的vuex;event bus: 利用一个中间组件来作为信息传递中介;

                g)better-scroll

                better-scroll是一个移动端滚动的解决方案,基于iscroll的重写(多年没人维护了,有很多bug;有些情况是基于js实现的帧动画,体验差,bs基于css3等)

                使用:首先应有一个父容器div,固定高度且overflow:hidden,给它设置bscroll,子元素高度由内容撑开。

 

***重要:在mounted钩子函数里,this.$nextTick的回调函数中初始化better-scroll。是因为wrapper的DOM在这个时候已经渲染了,可以正确计算其高度。

                异步数据处理


 

                初始化bs需要在数据获取之后。之所以放在created而不是mounted,是因为requestData是一个异步过程,拿到相应数据时,DOM已经渲染好,但是,数据改变后到DOM重新渲染仍然是异步过程,所以还是要异步初始化bs(nextTick)。

                注意:在PC上,点击事件会执行两次。由于better-scroll派发的事件有event_constructed:true属性。可以进行处理。

 if (!event._constructed) {
          return;
 }

        7、sass

            Sass的学名叫“CSS预处理器”,就是在CSS的基础上,引入了变量、嵌套、mixin(混合)、运算以及函数等功能,增加了代码的灵活性,可以让我们以更少的代码实现同样的效果,而且代码的整洁度、可读性更强。

            .scss是Sass3引入的新语法,基本写法与CSS大致相同

            基本语法:

                a)变量。css属性的值(1px,bold)都可替换为变量。

$box-color: red;        //定义变量
ul{
    color: $box-color;      //引用
}
li{
    background-color: $box-color;       //引用
}

                b)嵌套

/***********************************************选择器嵌套*******************************************/
div {
    h1 {
        color: #333;
    }
    p {
        margin-bottom: 1.4px;
        a {
            color: #999;
        }
        :hover{
            color: #888;
        }
    }
}

 /* 编译后 */
div h1 { color: #333; }
div p { margin-bottom: 1.4px; }
div p a { color: #999; }
div p:hover{ color: #888; }

/***********************************************属性嵌套*******************************************/
div {
    border: {
      style: solid;
      width: 1px;
      color: #ccc;
    }
}

//编译后
div {
  border-style: solid;
  border-width: 1px;
  border-color: #ccc;
}

                c)继承:使用选择器的继承,要使用关键词@extend,后面紧跟需要继承的选择器。

.class1 {
    border: 1px solid #333;
}

.class2 {
    @extend .class1;
    background-color: #999;
}

//编译后
.class1, .class2 {
  border: 1px solid #333;
}

.class2 {
  background-color: #999;
}

                d)Mixin混合器:使用@mixin声明,通过@include minxin名称调用

@mixin mixName {        
    float: left;
    margin-left: 10px;
}

div {
    @include mixName;
}

//编译后:
div {
  float: left;
  margin-left: 10px;
}
/*带参数的声明及调用*/
@mixin left($value: 10px) {
    float: left;
    margin-left: $value;
}
div {
    @include left(66px);
}

//编译后:
div {
  float: left;
  margin-left: 66px;
}

            e)颜色函数     

$box-color: red;
li{
 background-color: darken($box-color,30%);
}
//编译后
li{
background-color: #660000;
}
//更多
lighten(#cc3,10%)//#d6d65c
grayscale(#cc3)//#808080
complement(#cc3)//#33c

            f)导入:@import "地址";   如@import "../../common/scss/mixin.scss";

        8、优化:

            每次切换模块后,都会重新渲染DOM,解决方法为给APP.vue下的,组建的切换状态就会保留。

        9、打包:

        使用npm run build打包文件,其执行了node build/build.js脚本,最终产生一个dist目录,里面包含css,js,index.html文件,打包后文件通过HTTP server启动(sell总目录下创建一个produ.server.js写完代码后使用node prode.server.js启动)    

       技巧:(1).如果要使用new创建对象,由于本项目使用了ESlint检查代码规范,因此会报错,在这里使用/*eslint-disable no-new*/来跳过校验;

                 (2). 在build->webpack.base.conf.js中,module.exports下的resolve的alias下可以定义路径,就不用每次引用时加./表示当前路径  等类似问题了;

                 (3).图标与文字不齐,可设置vertical-align:top来对齐,还不行可以对图片设置paddingtop。

                 (4).手机测试网页技巧:将localhost换成自己的ip,然后复制地址栏地址,进入草料二维码,然后生成二维码,然后用手机扫一扫就可以查看了,前提是,你手机和电脑必须在同一个局域网

转载于:https://my.oschina.net/u/3728554/blog/1926349

你可能感兴趣的:(javascript,json,webpack,ViewUI)