精华内容
下载资源
问答
  • https://blog.csdn.net/qq_14863671/article/details/54412254我的博客的配套代码
  • vue饿了么app项目实战视频
  • 本项目是前端饿了么实战项目实战源码,适合前端基础学习和练习。几乎还原真实的商城,基本涵盖所有的页面和动画。简单易懂,适合有一定的javascript和vue基础小伙伴学习。
  • vuejs高仿饿了么app,十二章全,仅供学习,不得用于其他用途
  • 基于 vue vue-router vue-resource es6 stylus webpack 高仿饿了么外卖App商家详情
  • Vue仿饿了么APP

    2019-08-12 02:20:57
    Vue仿饿了么APP
  • 本教程是关于Vue学习与饿了么实战,可以学习到Vue以及饿了么
  • vue2.0 项目实战 饿了么APP,特别适合毕业设计、实习项目、学习检验,价值1999元免费赠送
  • Vue.js高仿饿了么外卖App学习记录

    千次阅读 2020-02-06 21:48:06
    (给达达前端加星标,提升前端技能)开发一款vue.js开发一款app,使用vue.js是一款高效的mvvm框架,它轻量,高效,组件化,数据驱动等功能便于开发。使用vue.js开发移动端a...

    (给达达前端加星标,提升前端技能)

    开发一款vue.js开发一款app,使用vue.js是一款高效的mvvm框架,它轻量,高效,组件化,数据驱动等功能便于开发。使用vue.js开发移动端app,学会使用组件化,模块化的开发方式。

    学习了如何根据需求分析开发,使用脚手架工具,数据mock,架构设计,自己测试,编译打包等流程。

    线上生产环境,如何考虑架构设计,组件抽象,模块拆分,代码风格统一,变量命名要求规范等优点。

    一款外卖app,商家页面,商家基本信息(顶部),商品区块,商品列表,分类列表,小球飞入购物车的动画。商品详情页,需要有顶部商品的大图,商品的详细信息,以及还有商品的评价列表。

    商品,评论列表,商家展示商家的详情信息。

    用vue-resource与后端做数据交互,vue-router前端路由,better-scroll的Js库等。使用vue-cli脚手架,搭建基本代码框架,vue-router官方插件管理路由。vue-resource是用于ajax通信的,webpack构建工具的使用。

    Vue是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。

    Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。

    目录/文件说明
    build项目构建(webpack)相关代码
    config配置目录,包括端口号等。我们初学可以使用默认的。
    node_modulesnpm 加载的项目依赖模块
    src

    包含了几个目录及文件:

    • assets: 放置一些图片,如logo等。

    • components: 目录里面放了一个组件文件,可以不用。

    • App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。

    • main.js: 项目的核心文件。

    static静态资源目录,如图片、字体等。
    test初始测试目录,可删除
    .xxxx文件这些是一些配置文件,包括语法配置,git配置等。
    index.html首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
    package.json项目配置文件。
    README.md项目的说明文档,markdown 格式

    说一说mvc和mvvm的区别

    mvc的全名是Model view Controller,是模型model,视图view,控制器controller的缩写,用一种业务逻辑,数据,界面显示分离的方法来写代码,view视图,视图层调用控制器到controller控制器,控制器调用model,model返回数据给控制器,然后控制器将数据返回给view。

    这是mvc的简单调用流程,mvc模式是单向的数据绑定,view视图层调用model层,要通过中间层controller来实现。

    mvvm模式是双向数据绑定,view,model,vm进行数据的绑定和事件的监听,对view和model进行监听,当有一方的值发生变化时,就更新另一个。

    数据响应原理

    组件化原理

    vue-cli,vue.js的开发利器,脚手架

    vue-cli可以搞定,目录结构,本地调试,代码部署,热加载,单元测试。

    vue-cli的安装方法:

    node -v

    mac 

    sudo npm install -g vue-cli

    使用webpack模板,名字sell,外卖app。

    运行效果:

    然后把项目放进你的编辑器

    mode_modules文件夹:npm install 安装的依赖代码库

    src文件夹是我们存放的源码

    这个文件跟我不一样也没事。

    editorconfig是编辑器的配置

    eslintignore为忽略语法检查的目录文件

    eslintrc.js为eslint的配置文件

    商品页面:

    商品页_公共以及优惠信息

    商品页购物车详情

    商品页面_商品详情页面

    评价页

    商家页

    设备像素比devicePixelRatio

    在移动端,devicePixelRatio指的是window.devicePixelRatio。

    移动端设备分为非视网膜屏幕和视网膜屏幕。

    window.devicePixelRatio是设备上物理像素和设备独立像素的比例,公式表就是:window.devicePixeRatio = 物理像素/dips。

    icomoon.io,图标字体制作

    mock数据,模拟后台数据

    icon- 开头的图标(如图所示) 

    首先进入网页https://icomoon.io/ 

    然后点击右上角的“IcoMoon APP”按钮,选择导入自己的SVG图来生成ico-的图标,点击新页面左上角的“Inport ICONS”。 

    在devServer下面加入

    页面骨架开发

    sell->build->confi->node_modules->resource, img, psd, svg ->src, common->components, app.vue->static

    <html>
    <head>
      <meta charset="utf-8">
        <title>sell</title>
        <meta name="viewport"
        content="width=device-width,initial-scale=1.0,maxinum-scale=1.0,
        minimun-scale=1.0,user-scalable=no">
        <link rel="stylesheet" type="text/css" href="static/css/reset.css">
    </head>
    </body>
    <app></app>
    </body>
    </html>
    

    meta name="viewport"

    它是移动端浏览器在一个比屏幕更宽的虚拟窗口中渲染页面,用来实现展示没有做移动端适配的网页,可以完整的展示给用户,viewport的宽度就是可显示区域的宽度。

    <meta name="viewport"
        content="width=device-width,initial-scale=1.0,maxinum-scale=1.0,
        minimun-scale=1.0,user-scalable=no">
    

    这些属性可以混合使用,width控制视图窗口的宽度,height控制视图窗口的高度,这个属性很少用,initial-scale为控制页面最初加载时在最理想的情况下缩放的等级,通常设置为1.0,可以是小数,maximum-scale为允许用户的最大缩放量,minimum-scale为允许用户的最小缩放量。

    user-scalable为是否允许用户进行缩放,值只能“no”或者“yes”。no为不允许,yes为允许。

    width和initial-scale设置了两者,浏览器会自动选择数值最大的进行适配。

    就是当窗口的最适配理想宽度为300时,initial-scale的值设置为1时,width设置的值为400,那么取最大值,400。

    当窗口的最适配理想值为500时,那么取的值为500。

    width=device-width和initial-scale=1都表示为最理想的viewport,但是在ipad,iphone等移动设备,ie上,横竖屏不分,默认都为竖屏的宽度,兼容的最好写法。

    什么是viewport,它是用户网页的可视区域,翻译就是视区。

    手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。

    没有添加viewport的效果:

    加了viewport的效果:

    viewport这个特性被用于移动设备,但是也可以用在支持类似“固定到边缘”等特性的桌面浏览器,如微软的edge。

    按百分比计算尺寸的时候,就是参照的初始视口,它指的是任何用户代理和样式对它进行修改之前的视口。桌面浏览器如果不是全屏模式的话,一般是基于窗口大小。

    在移动设备上,初始视口通常就是应用程序可以使用的屏幕部分。

    在viewport中就是浏览器上用来显示网页的那部分区域。

    width=device-width能使所有浏览器当前的viewport宽度变成理想的宽度,initial-scale=1是将页面的初始缩放值设置为1。用来将viewport的宽度变成为理想的宽度,防止横向滚动条出现。

    <meta name="viewport" content="width=device-width, user-scalable=no,
    initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0">
    

    width=device-width表示为宽度是设备屏幕的宽度

    initial-scale=1.0表示为初始的缩放比例

    minimum-scale=0.5表示为最小的缩放比例

    maximum-scale=2.0表示为最大的缩放比例

    user-scalable=yes表示用户是否可以调整缩放比例

    设备像素,设备独立像素,css像素掌握

    设备像素就是屏幕上的真实像素点,iphone6的设备像素像素为750*1334,则屏幕上有750*1334个像素点;设备独立像素,操作系统定义的一种长度单位,iphone6的设备独立像素375*667,正好是设备像素的一半,css像素,css中的长度单位,在css中使用px都是指css像素。

    物理像素来代表设备像素,独立像素代表设备独立像素。

    在很早的时候,只有物理像素,没有独立像素,在不缩放的前提,css中的1px代表着一个物理像素。

    不过从iphone4开始,推出了retina屏幕,物理像素变成640*960,屏幕尺寸没有变化,在单位面积上的物理像素的数量增加了,则表示屏幕密度增加了。按照原来,1px css像素由1个物理像素来渲染,那么width:320px的元素就会占据半个屏幕的宽度。

    1个独立像素==2个物理像素

    viewport是浏览器窗口,代表浏览器的可视区域,就是浏览器中用来显示网页的部分区域。

    像素单位有设备像素,逻辑像素,css像素。

    设备像素也叫物理像素。

    什么是设备像素,它指的是显示器上的真实像素,每个像素的大小是屏幕固有的属性。

    设备分辨率是用来描述这个显示器的宽和高分别有多少个设备像素。

    设备像素和设备分辨率由操作系统来管理。

    全局安装vue-cli脚手架工具

    cnpm install -g vue-cli
    

    初始化sell项目

    vue init webpack sell
    

    进入sell目录

    cd sell
    

    安装依赖

    cnpm install
    

    运行项目

    cnpm run dev 或者 node build/dev-server.js
    

    写mock数据接口

    // 文件位置:build/dev-server.js
    // 注:此处是关键代码
    var app = express()
    
    
    var appData = require('../data.json')
    var seller = appData.seller
    var goods = appData.goods
    var ratings = appData.ratings
    
    
    var apiRoutes = express.Router()
    apiRoutes.get('/seller', function (req, res) {
      res.json({
        error: 0,
        data: seller
      })
    })
    apiRoutes.get('/goods', function (req, res) {
      res.json({
        error: 0,
        data: goods
      })
    })
    apiRoutes.get('/ratings', function (req, res) {
      res.json({
        error: 0,
        data: ratings
      })
    })
    
    
    app.use('/api', apiRoutes)
    

    项目实战,页面骨架开发

    webstorm设置文件的默认结构

    <template>
    
    
    </template>
    
    
    <script type="text/ecmascript-6">
        export default {}
    </script>
    
    
    <style lang="stylus" rel="stylesheet/stylus">
    </style>
    

    安装ajax异步请求插件vue-resource

    cnpm install vue-resource --save-dev
    

    文件位置:src/APP.vue

    <template>
      <div>
        <v-header :seller="seller"></v-header>
        <div class="tab border-1px">
          <div class="tab-item">
            <router-link to="/goods">商品</router-link>
          </div>
          <div class="tab-item">
            <router-link to="/ratings">评论</router-link>
          </div>
          <div class="tab-item">
            <router-link to="/seller">商家</router-link>
          </div>
        </div>
        <!-- 路由外链 -->
        <keep-alive>
          <router-view :seller="seller"></router-view>
        </keep-alive>
      </div>
    </template>
    
    
    <script type="text/ecmascript-6">
      import {urlParse} from './common/js/util';
      import header from './components/header/header.vue';
    
    
      const ERR_OK = 0; 
    
    
      export default {
        data() {
          return {
            seller: {
              id: (() => {
                let queryParam = urlParse();
                return queryParam.id;
              })()
            }
          }
        },
        created() {
          this.$http.get('/api/seller?id=' + this.seller.id).then(response => {
            response = response.body; 
            if (response.error === ERR_OK) {
              this.seller = Object.assign({}, this.seller, response.data);
              console.log(this.seller.id);
            }
          }, response => {
          });
        },
        components: {
          'v-header': header
        }
      }
    </script>
    
    
    <style lang="stylus" rel="stylesheet/stylus">
      @import "common/stylus/mixin.styl"
      .tab
        display: flex
        width: 100%
        height: 40px
        border-1px(rgba(7, 17, 27, 0.1))
        line-height: 40px
        .tab-item
          flex: 1
          text-align: center
          & > a
            display: block
            font-size: 14px
            color: rgb(77, 85, 93)
            &.active
              color: rgb(240, 20, 20)
    </style>
    

    文件位置:src/router/index.js

    import Vue from 'vue';
    import Router from 'vue-router';
    import goods from '@/components/goods/goods.vue';
    import ratings from '@/components/ratings/ratings.vue';
    import seller from '@/components/seller/seller.vue';
    
    
    Vue.use(Router);
    
    
    const routes = [{
      path: '/',
      component: goods
    }, {
      path: '/goods',
      component: goods
    }, {
      path: '/ratings',
      component: ratings
    }, {
      path: '/seller',
      component: seller
    }];
    
    
    export default new Router({
      linkActiveClass: 'active',
      routes: routes
    });
    

    文件位置:src/main.js

    import Vue from 'vue';
    import App from './App.vue';
    import router from './router';
    import VueResource from 'vue-resource';
    
    
    Vue.config.productionTip = false;
    
    
    import '../static/css/reset.css';
    import './common/stylus/base.styl';
    import './common/stylus/index.styl';
    import './common/stylus/icon.styl';
    Vue.use(VueResource);
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    });
    

    安装better-scroll

    cnpm install better-scroll --save-dev
    

    export default {
      created() {
        this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];
        this.$http.get('/api/goods').then(response => {
          response = response.body; 
          if (response.error === ERR_OK) {
            this.goods = response.data;
            console.log(this.goods);
            this.$nextTick(() => {
              this._initScroll();
              this._calculateHeight();
            })
          }
        }, response => {
        });
      }
    }
    

    export default {
        methods: {
          selectMenu(index, event) {
            if (!event._constructed) {
              return;
            }
            console.log(index);
            let foodList = this.$refs.foodsWrapper.getElementsByClassName('food-list-hook');
            let el = foodList[index];
            this.foodsScroll.scrollToElement(el, 300);
          },
          _initScroll() {
            this.menuScroll = new BScroll(this.$refs.menuWrapper, {
              click: true 
            });
            this.foodsScroll = new BScroll(this.$refs.foodsWrapper, {
              click: true,
              probeType: 3 
            });
    
    
            this.foodsScroll.on('scroll', (pos) => {
              this.scrollY = Math.abs(Math.round(pos.y));
            })
          },
          _calculateHeight() {
            let foodList = this.$refs.foodsWrapper.getElementsByClassName('food-list-hook');
            let height = 0;
            this.listHeight.push(height);
            for (let i = 0; i < foodList.length; i++) {
              let item = foodList[i];
              height += item.clientHeight;
              this.listHeight.push(height);
            }
          }
        },
        components: {
          shopcart,
          cartcontrol
        }
    }
    

    Vue.set(this.food, 'count', 1);
    

    小球动画函数监听

    export default {
        methods: {
            drop(el) {
                for (let i = 0; i < this.balls.length; i++) {
                    let ball = this.balls[i];
                    if (!ball.show) {
                        ball.show = true;
                        ball.el = el;
                        this.dropBalls.push(ball);
                        return;
                    }
                }
            },
    
    
            beforeDrop: function (el) {
                let count = this.balls.length;
                while (count--) {
                    let ball = this.balls[count];
                    if (ball.show) {
                        let rect = ball.el.getBoundingClientRect();
                        let x = rect.left - 32;
                        let y = -(window.innerHeight - rect.top - 22);
                        el.style.display = '';
                        el.style.webkitTransform = `translate3d(0,${y}px,0)`;
                        el.style.transform = `translate3d(0,${y}px,0)`;
                        let inner = el.getElementsByClassName('inner-hook')[0];
                        inner.style.webkitTransform = `translate3d(${x}px,0,0)`;
                        inner.style.transform = `translate3d(${x}px,0,0)`;
                        console.log(el, x, y);
                    }
                }
            },
    
    
            dropping: function (el, done) {
                let rf = el.offsetHeight; 
                this.$nextTick(() => {
                    el.style.display = '';
                    el.style.webkitTransform = 'translate3d(0,0,0)';
                    el.style.transform = 'translate3d(0,0,0)';
                    let inner = el.getElementsByClassName('inner-hook')[0];
                    inner.style.webkitTransform = 'translate3d(0,0,0)';
                    inner.style.transform = 'translate3d(0,0,0)';
                    el.addEventListener('transitionend', done);
                });
            },
            afterDrop: function (el) {
                let ball = this.dropBalls.shift();
                if (ball) {
                    ball.show = false;
                    el.style.display = 'none';
                }
            }
        }
    }
    

    文件位置:src/common/js/date.js

    export function formatDate(date, fmt) {
    
    
      if (/(y+)/.test(fmt)) {
        fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
      }
      let o = {
        'M+': date.getMonth() + 1,
        'd+': date.getDate(),
        'h+': date.getHours(),
        'm+': date.getMinutes(),
        's+': date.getSeconds()
      };
      for (let k in o) {
        if (new RegExp(`(${k})`).test(fmt)) {
          let str = o[k] + ''; 
          fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
        }
      }
      return fmt;
    }
    
    
    function padLeftZero(str) { 
      return ('00' + str).substr(str.length);
    }
    
    
    
    
    import {formatDate} from '../../common/js/date'; 
        filters: { 
            formatDate(time) {
                let date = new Date(time);
                return formatDate(date, 'yyyy-MM-dd hh:mm');
          }
        }
    }
    

    export default {
      mounted() {
        console.log('mounted'); 
        this._initScroll();
        this._initPics();
      },
      updated() {
        console.log('updated'); 
        this._initScroll();
        this._initPics();
      }
    }
    

    本地存储相关操作封装

    文件位置:src/common/js/store.js

    // 存储到本地存储
    export function saveToLocal(id, key, value) {
      let seller = window.localStorage.__seller__; 
      if (!seller) {
        seller = {};
        seller[id] = {};
      } else {
        seller = JSON.parse(seller);
        if (!seller[id]) {
          seller[id] = {};
        }
      }
      seller[id][key] = value;
      window.localStorage.__seller__ = JSON.stringify(seller);
    }
    // 从本地存储里面读取
    export function loadFromLocal(id, key, def) {
      /* eslint-disable semi */
      let seller = window.localStorage.__seller__;
      if (!seller) {
        return def;
      }
      seller = JSON.parse(seller)[id];
      if (!seller) {
        return def;
      }
      let ret = seller[key];
      return ret || def;
    }
    

    解析url参数

    文件位置: src/common/js/util.js

    export function urlParse() {
      let url = window.location.search;
      let obj = {};
      let reg = /[?&][^?&]+=[^?&]+/g;
      let arr = url.match(reg);
      if (arr) {
        arr.forEach((item) => {
          let tempArr = item.substring(1).split('=');
          let key = decodeURIComponent(tempArr[0]);
          let val = decodeURIComponent(tempArr[1]);
          obj[key] = val;
        })
      }
      return obj;
    }
    

    项目编译打包

    cnpm run build
    

    配置打包规范:config/index.js

    module.exports = {
      build: {
        productionSourceMap: true, 
        port: 9000 
      },
      dev: {
    
    
      }
    }
    

    利用express编写一个本地服务器

    文件位置:./prod.server.js

    let express = require('express');
    let config = require('./config/index');
    
    
    let port = process.env.PORT || config.build.port;
    
    
    let app = express();
    
    
    let router = express.Router();
    
    
    router.get('/', function (req, res, next) {
      req.url = '/index.html';
      next();
    });
    
    
    app.use(router);
    let appData = require('./data.json');
    let seller = appData.seller;
    let goods = appData.goods;
    let ratings = appData.ratings;
    
    
    let apiRoutes = express.Router();
    apiRoutes.get('/seller', function (req, res) {
      res.json({
        error: 0,
        data: seller
      })
    });
    apiRoutes.get('/goods', function (req, res) {
      res.json({
        error: 0,
        data: goods
      })
    });
    apiRoutes.get('/ratings', function (req, res) {
      res.json({
        error: 0,
        data: ratings
      })
    });
    
    
    app.use('/api', apiRoutes);
    
    
    app.use(express.static('./dist'));
    
    
    module.exports = app.listen(port, function (err) {
      if (err) {
        console.log(err);
        return;
      }
      console.log('Listening at http://localhost:' + port);
    });
    

    Eslint规范总体设置

    项目开发流程

    需求分析,脚手架工具,数据mock,架构设计,代码编写,自测,编译打包。

    可以看看别人的代码

    仿【饿了么】订餐软件的一个demo

    https://github.com/guxun12/ele_demo

    参考资料&资源

    慕课网视频,Vue.js高仿饿了么外卖App

    Vue.js 高仿饿了么外卖 App 课程源码,课程地址: http://coding.imooc.com/class/74.html

    推荐阅读  点击标题可跳转

    【面试Vue全家桶】vue前端交互模式-es7的语法结构?async/await

    【面试需要-Vue全家桶】一文带你看透Vue前端路由

    【面试需要】掌握JavaScript中的this,call,apply的原理

    2019年的每一天日更只为等待她的出现,好好过余生,庆余年 | 掘金年度征文

    进来就是一家人【达达前端技术社群⑥】

    这是一个有质量,有态度的公众号

    点关注,有好运

    展开全文
  • 本系列课程是继饿了么订餐app1和2继续开发的课程, 主要讲解的核心功能包含商品列表, 商品详情以及购物车.
  • 本系列课程是继续饿了么3之后继续开发的, 实现了微信支付 项目打包 以及服务器部署, 以及前端微信支付流程, 还有后端微信支付流程的内容.
  • 注意:新版的vue-cli 自动搭建的build 文件里没有dev-server.js 和 dev-client.js ,因此我们要在webpack.dev.conf.js 里配置 复制data.json 到src/static/该项目下 找到bulid目录下 webpack.dev.conf.js 找到 const...

    mack数据

    如果后端接口尚未开发完成,前端开发一般使用mock数据。
    注意:新版的vue-cli 自动搭建的build 文件里没有dev-server.js 和 dev-client.js ,因此我们要在webpack.dev.conf.js 里配置

    复制data.json 到src/static/该项目下

    找到bulid目录下 webpack.dev.conf.js 找到 const portfinder = require(‘portfinder’),在其下添加mock 数据

    // 添加mock 数据
    const express = require('express')
    const app = express()
    var appData = require('../static/data.json')//加载本地数据文件
    var seller=appData.seller;
    var goods=appData.goods;
    var ratings=appData.ratings;
    var apiRoutes = express.Router()
    app.use('/api', apiRoutes)
    

    接着找到 devServer 里的 watchOptions,其后紧跟

    watchOptions: {
          poll: config.dev.poll,
        },
        before(app) {
          app.get('/api/seller', (req, res) => {
            res.json({
              errno: 0,
              data: seller
            })//接口返回json数据,上面配置的数据appData就赋值给data请求后调用
          }),
          app.get('/api/goods', (req, res) => {
            res.json({
              errno: 0,
              data: goods
            })
          }),
          app.get('/api/ratings', (req, res) => {
            res.json({
              errno: 0,
              data: ratings
            })
          })
        }
    

    npm run dev 运行 访问http://localhost:8080/api/seller 就可接收到 该路由对应的json 数据

    关于路由 vue-router

    Vue1.0和Vue2.x的区别还是蛮大的 Vue2.x做的改变更方便我们实现路由的加载 我是直接在components里创建三个组件,然后在router/index.js里加载组件

    import goods from 'components/goods/goods'
    import seller from 'components/seller/seller'
    import ratings from 'components/ratings/ratings'
    
    Vue.use(Router)
    
    export default new Router({
        routes:[
            {
                path:'/',
                redirect:'/goods' //默认其实页面
            },
            {
                path:'/goods',
                component:goods
            },
            {
                path:'/seller',
                component:seller
            },
            {
                path:'/ratings',
                component:ratings
            }
        ]
    })
    

    然后定义一个tab组件 在App.vue里之间导入组件 在tab组件里引入之前创建三个组件

    <div class="tab border-1px">
            <router-link tag="a" to="/goods" class="tab-item">商品</router-link>
            <router-link tag="a" to="/ratings" class="tab-item">评价</router-link>
            <router-link tag="a" to="/seller" class="tab-item">商家</router-link>
    </div>
    

    axios 请求数据

    安装 axios

    npm install axios
    引入axios组件 import axios from ‘axios’

    axios 请求数据(在此之前创建一个接受数据的对sellerobj)

    export default {
     //  获取数据 准备  返回一个对象,后台获取数据后 赋予 该对象
       data (){
       	 return {
       	 	 seller:{}
       	 }
       },
       created (){ //  创建之前 请求数据
       	 axios.get('static/data.json').then((result) => {
       	  	 console.log(result) //  控制台检查  数据存储在  result.data 里  
       	  	this.sellerobj = result.data.seller //  将数据存到sellerobj里  	 	
       	  })
       }
    }
    

    项目的初始化工作就差不多完成了!!! 后面就开始开发header组件-

    展开全文
  • ├─01 VueCli3实战项目-还原eleme订餐App1(短信验证码登录和高德定位) │ 001 VueCli3-饿了吗项目成果展示和注意事项.mp4 │ 002 VueCli3-构建项目和准备工作.mp4 │ 003 VueCli3-构建登录组件.mp4 │ 004 VueCli3-...
  • vue.js高仿饿了么(前期整理)

    千次阅读 2018-03-16 09:24:47
    1、熟悉项目开发流程需求分析——&gt;脚手架工具——&gt;数据mock——&gt;架构设计——&gt;代码编写——&...3、掌握Vue.js在实战中应用4、学会使用Vue.js完整地开发移动端App5、学会...

    1、熟悉项目开发流程

    需求分析——>脚手架工具——>数据mock——>架构设计——>代码编写——>自测——>编译打包。

    2、熟悉代码规范

    从架构设计、组件抽象、模块拆分,到代码风格统一、CSS代码规范和JavaScript变量命名规范,以标准写代码,开发出扩展性、通用性强的优质代码。

    3、掌握Vue.js在实战中应用

    4、学会使用Vue.js完整地开发移动端App

    5、学会工程化开发、组件化开发和模块化开发的方式

    6、酷炫的交互设计

     

    所用到的技术

    后端:vue-resource(ajax通信)

    前端:vue-router(官方插件管理路由)、localstorage、flex布局、css sticky footer布局、html、css、es6、Vue-cli(脚手架,用来搭建基本代码框架)、vue(热门前端框架)

    其他:webpack(构建工具)、eslint(代码风格检查工具)

    第三方库:better-scroll

     

    Vue.js出现的历史原因也是前端的发展趋势

    1、旧浏览器逐渐淘汰,移动端需求增加;

    2、前端交互越来越多,功能越来越复杂;

    3、架构从传统后台MVC向REST API+前端MV*(MVC、MVP、MVVM)迁移。

     

    MVVM框架具有的优点

    1、针对具有复杂交互逻辑的前端应用;

    2、提供基础的架构抽象;

    3、通过Ajax数据持久化,保证前端用户体验。

    下面这张图充分说明了什么是MVVM框架,也说明vue.js双向数据绑定的基本原理:

     

     

    什么是vue.js

    它是一个轻量级MVVM框架,主要用于数据驱动+组件化的前端开发。它具有以下特点(数据驱动和组件化为核心思想):

    1、轻量级(大小只有20k+)

    2、简洁(容易上手,学习曲线平稳)

    3、快速

    4、组件化:扩展HTML元素,封装可重用的代码。设计的原则为(1)页面上每个独立的可视/可交互区域视为一个组件;(2)每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护;(3)页面不过是组件的容器,组件可以嵌套自由组合,形成完整的页面。

    5、数据驱动:DOM是数据的一种自然映射,看下面两张图进行理解:

             

    结合上面两张图,再看看下面一张图,进一步理解vue.js实现双向数据绑定的原理(又称为数据响应原理,即数据【model】改变驱动视图【view】自动更新):

    6、模块友好

     

    Vue-cli介绍

    这是一款Vue的脚手架工具,脚手架的含义就是编写好基础的代码。vue-cli帮助我们编写好了目录结构、本地调试、代码部署、热加载和单元测试。

    github地址:https://github.com/vuejs/vue-cli

     

    安装Vue-cli

    基本教程戳这里

    【注意】

    初次使用,千万不要启动ESLint语法规范。

     

    webpack打包

    webpack就是将各种资源打包,然后输出js、图片、css静态文件。

     

     

    新姿势

    设备像素比(DPR)

     

    图标字体的制作

    打开https://icomoon.io/ => 点击右上角icomoon app => 点击左上角import icons =>选择做好的svg文件 => 点击左上角untitled set选择上图标 => 点击右下角generate fonts =>再点击右下角download即可下载(左上角preferences是修改下载文件夹的名称)。

     

    使用图标字体

    设计好项目目录,将fonts文件夹下的文件复制粘贴进项目中,将style.css复制粘贴进stylus目录中,并改名为icon.styl,同时将里面的内容改为stylus语法

     

    mock数据

    作为前端经常需要模拟后台数据,我们称之为mock,通常的方式为自己搭建一个服务器或者创建一个json文件,返回我们想要的数据。

     在这一步有个坑,就是vue-cli更新了,很多配置都发生了变更。在这里有很好的解决方法。下面贴上webpack.dev.conf.js更改后的代码

      View Code

    没有启动ESlint语法检查的webpack.dev.conf.js的代码

      View Code

    为了更好的查看调取api回来的数据,建议安装Google的jsonview插件。然后在浏览器查看是否成功返回数据,测试:http://localhost:8080/api/goods

    此时在项目中导入了一个data.json文件

     

     

    组件拆分部分(一) 启动ESlint语法时,对各种格式的检查到了骇人的地步,多个;和换个行都能报warning!并且js文件的最后还要求换行!注释还要遵守规范!!

    步骤一:导入static文件reset.css

    步骤二:删除默认组件HelloWorld.vue和assets文件夹,修改router中的index.js

      View Code

    步骤三:分别配置App.vue和main.js

      View Code
      View Code

    步骤四:增加一个header.vue文件

      View Code

     

    组件拆分部分(二) 

    由于需要用到stylus语法,因此事先得安装stylus 和 stylus-loader的相关依赖包

    步骤一:修改App.vue文件

      View Code

     

    配置路由规则

    配置路由规则没什么难度,去官方网站瞧一瞧就行了,这里有个linkActiveClass属性,挺有用的。下面稍微看一看配置过程

    步骤一:创建一个goods.vue文件,其他两个ratings.vue和seller.vue类似

      View Code

    步骤二:在index.js文件中配置路由规则

      View Code

    另一种路由规则配置

      View Code

    步骤三:配置根组件App.vue

      View Code

     

    在局域网内,通过手机访问webapp项目

    命令行:ipconfig查询本机IP => 用IP代替localhost => 将地址复制到草料二维码的官方网站生成二维码 => 用微信扫一扫(假如微信扫不了的话,下载一个二维码扫描来扫描)

    【注意】

    需要解决ip地址无法访问vue项目的问题

    1、将config文件夹中的index.js文件修改

      View Code

    2、重启服务

     

    由于DPR引发的1px问题以及解决方式

    步骤一:创建一个mixin.styl文件,作为边框的公共样式

      View Code

    步骤二:创建一个base.styl文件,解决1px问题

      View Code

    步骤三:创建一个index.styl文件,统一导入styl文件

      View Code

    步骤四:修改icon.styl文件,需要更改url路径,不然会报错

      View Code

    步骤五:配置router文件夹下的index.js文件

      View Code

    步骤六:在App.vue使用写好的styl样式

      View Code

     

    编辑.eslintrc.js的规则

    假如在创建项目中出现如下情况

    那么就打开.eslintrc.js文件,将其规则忽略掉(设置为0)

     

    清除掉令人抓狂的eslintrc语法规则!

      View Code

     

     

    使用vue-resource

    步骤一:安装cnpm install vue-resource --save

    步骤二:配置router文件夹中的index.js文件

      View Code

    步骤三:配置App.vue文件

      View Code

     

    切记

    导入stylus样式表必须在style作如下的定义

    <style scoped lang="stylus" rel="stylesheet/stylus"></style> 

     

    外部组件(一)

    步骤一:修改App.vue,将seller对象的数据传递给组件header.vue

      View Code

    步骤二:编写header.vue组件

      View Code

     

    外部组件(二)

    步骤一:将所需要的图片导入到header文件夹中

    步骤二:编写mixin.styl文件,目的是让程序在不同设备下显示不同的图片大小

      View Code

    步骤三:编写base.styl文件,目的是统一页面字体

      View Code

    步骤四:在header.vue文件中增加样式

      View Code

     

    外部组件(三)

     继续编写header.vue文件,当然相关的图片也要导入进来。我们可以通过修改<span class="icon" :class="classMap[seller.supports[0].type]"></span>的数值来决定要显示的图片,对内容显示操作也是如此:

    <span class="text">{{seller.supports[0].description}}</span>

      View Code

     

    外部组件(四)

    继续编写header.vue文件

      View Code

     

    外部组件(五)

    继续编写header.vue文件,增加公告部分

      View Code

     

    外部组件(六)

     继续编写header.vue文件,增加顶部蒙层效果

      View Code

     

    详情弹层页(一)

     继续编写header.vue文件,增加详情弹层效果

      View Code

     

    详情弹层页(二)

    sticky footers布局相关知识

     继续编写header.vue文件,设置弹窗关闭按钮,利用sticky footers知识

      View Code

    编写base.styl文件,设置清除浮动样式

      View Code

     

    详情弹层页(三、四)

    步骤一:新建一个通用的组件star.vue

      View Code

    步骤二:继续编写header.vue文件

      View Code

     

    详情弹层页(五)

    继续编写header.vue文件,增加响应式的水平线条

      View Code

     

    食品组件布局(一)

    创建goods.vue组件,首先编写食品左侧内容

      View Code

     

    食品组件布局(二)

    编写goods.vue组件,增加右侧内容

      View Code

     

    食品组件布局(三)

    继续编写goods.vue组件,增加样式

      View Code

     

    食品组件布局(四)

    继续编写goods.vue组件,完成样式部分

      View Code

     

    使用better-scroll(一)

    插件地址:https://github.com/ustbhuangyi/better-scroll

    步骤一:下载安装cnpm install better-scroll --save

    步骤二:编写goods.vue组件,让页面滚动起来

      View Code

     

    使用better-scroll(二)

    编写goods.vue组件,监测右侧页面高度

      View Code

     

    使用better-scroll(三)

    编写goods.vue组件,实现右侧滚动左边实时发生变化

      View Code

     

    使用better-scroll(四)

    编写goods.vue组价,完全实现左右联动

      View Code

     

    购物车组件(一)

    步骤一:创建一个shopcart.vue组件,编写好基础的样式

      View Code

    步骤二:配置好goods.vue组件

      View Code

     

    购物车组件(二)

    继续编写shopcart.vue组件,增加样式

      View Code

     

    购物车组件(三)

    步骤一:修改App.vue根组价,传递值

      View Code

    步骤二:修改goods.vue组件,传递值

      View Code

    步骤三:编写shopcart.vue组件,接收值并增加样式

      View Code

     

     购物车组件(四)

    继续编写shopcart.vue组件,为商品价格计算做前期编码

      View Code

     

    购物车组件(五)

    继续编写shopcart.vue组件,实现样式动态改变

      View Code

     

    购物车组件(六)

    继续编写shopcart.vue组件,基本完成全部效果

      View Code

     

     cartcontrol组件(一)

    步骤一:新建cartcontrol.vue组件,作为购物车的添加按钮

      View Code

    步骤二:在goods.vue组件中调用cartcontrol.vue组件

      View Code

     

     cartcontrol组件(二)

     继续编写cartcontrol.vue组件,进一步实现购物车按钮效果

      View Code

     

     cartcontrol组件(三)

    步骤一:编写cartcontrol.vue组件,增加食品增加和减少动画效果

      View Code

    步骤二:编写goods.vue组件,将按钮和购物车区实现联动效果

      View Code

     

    购物车小球动画实现(一)

    【注意】无法实现

    步骤一:编写goods.vue组件

      View Code

    步骤二:编写carcontrol.vue组件

      View Code

    步骤三:编写shoucart.vue组件

      View Code

     

    购物车详情页(一、二)

    编写shopcart.vue组件,实现初步效果

      View Code

     

    购物车详情页(三)

    继续编写shopcart.vue组件,实现增加和减少功能

      View Code

     

    购物车详情页(四)

    继续编写shopcart.vue组件,实现蒙层效果

      View Code

     

    商品详情页实现(一)

    步骤一:编写goods.vue组件

      View Code

    步骤二:新建food.vuez组件

      View Code

     

    商品详情实现(二)

    步骤一:编写goods.vue组件

      View Code

    步骤二:编写food.vue组件,实现切换动画效果

      View Code

     

    商品详情实现(三)

    编写food.vue组件,实现后退效果以及部分内容展示

      View Code

     

    商品详情实现(四)

    编写food.vue组件,增加cartcontrol.vue组件

      View Code

     

    商品详情实现(五)

    步骤一:编写food.vue组件,实现添加购物车按钮(动画效果依然无法实现)

      View Code

    步骤二:编写cartcontrol.vue组件,阻止点击事件冒泡行为

      View Code

     

    split组件实现

    步骤一:新建split.vue组件

      View Code

    步骤二:编写food.vue组件,继续添加内容和添加split.vue组件

      View Code

     

    ratingselect组件(一)

    步骤一:新建ratingselect.vue组件

      View Code

    步骤二:编写food.vue组件,将ratingselect.vue组件加载

      View Code

     

    ratingselect组件(二)

    编写food.vue组件,实现部分ratingselect.vue效果

      View Code

     

    ratingselect组件(三)

    继续编写ratingselect.vue组件,实现部分样式和动态切换

      View Code

     

    ratingselect组件(四)

    继续编写ratingselect.vue组件,进一步实现样式

      View Code

     

    ratingselect组件(五)

    继续编写ratingselect.vue组件,完成全部切换效果(点击效果无效)

      View Code

     

    评价列表(一)

    编写好food.vue组件的评价结构

      View Code

     

    评论列表(二)

    继续编写food.vue组件的评论区样式

      View Code

     

    评论列表(三)

    继续编写food.vue组件,实现评价切换效果(失败)

      View Code

     

    评论列表(四、五、六)

    步骤一:编写food.vue组件,创建一个时间过滤器

      View Code

    步骤二:编写公共的date.js文件,实现时间过滤的效果

      View Code

     

    rating组件开发(一)

    编写ratings.vue组件,完成左边部分样式

      View Code

     

    rating组件开发(二)

    继续编写ratings.vue组件,完成右边部分样式

      View Code

     

    rating组件开发(三)

    继续编写ratings.vue组件,利用media实现响应式功能

      View Code

     

    rating组件开发(四)

    继续编写ratings.vue组件,实现评论区内容展示

      View Code

     

    rating组件开发(五)

    继续编写ratings.vue组件,实现评论区滚动功能和相关样式

      View Code

     

    rating组件开发(六)

    完善ratings.vue组件切换“满意、不满意”的效果(失败)

      View Code

     

    seller组件开发(一)

    编写seller.vue组件,建立初步的头部结构

      View Code

     

    seller组件开发(二)

    编写seller.vue组件,建立初步的头部结构样式

      View Code

     

    seller组件开发(三)

    编写seller.vue组件,公告与活动初次开发

      View Code

     

    seller组件开发(四)

    编写seller.vue组件,公告与活动二次开发,并且实现滚动功能

      View Code

     

    seller组件开发——商家实景图(五)

    编写seller.vue组件,实现商家实景图效果

      View Code

     

    seller组件开发——商家信息(六)

    编写seller.vue组件,实现商家信息部分

      View Code

     

    seller组件开发——收藏商家(一)

    编写seller.vue组件,实现商家收藏基本效果

      View Code

     

    seller组件开发——收藏商家(二)

    步骤一:编写App.vue根组件,为传递商家ID值做前期准备

      View Code

    步骤二:新建util.js文件,实现查询的效果

      View Code

     

    seller组件开发——收藏商家(三)

    步骤一:新建store.js文件,实现存储状态的功能

      View Code

    步骤二:编写seller.vue组件,将数据传入store.js中

      View Code

     

    体验优化

    编写App.vue组件实现状态的保留,原理是将当前的状态保存在内存中,使用的keep-alive标签。

      View Code

     

    分类:  vue.js
    展开全文
  • vue饿了么app.txt

    2019-06-15 14:12:29
    vue饿了么app项目实战视频,里面会有vue-cli和webpack打包,还有设备像素比和flex布局讲解
  • Vue实例没有el属性时,则该实例尚没有挂载到某个dom中;假如需要延迟挂载,可以在之后手动调用vm.$mount()方法来挂载。 new Vue({ router, render: h => h(App) }).$mount("#app"); ` `new Vue({ el: '#...

    一、$mount()手动挂载

    当Vue实例没有el属性时,则该实例尚没有挂载到某个dom中;假如需要延迟挂载,可以在之后手动调用vm.$mount()方法来挂载。

    new Vue({
       router,
       render: h => h(App)
     }).$mount("#app");
    `
    `new Vue({
      el: '#app',
      router,
      render: h => h(App) 
    });

    解释: render: x => x(App)

       这里的render: x =>x(App)是es6的写法
         转换过来就是:暂且可理解为是渲染App组件
         render:(function(x){
              return x(App);
          });

    二、mock数据

    如果后端接口尚未开发完成,前端开发一般使用mock数据。
    注意:新版的vue-cli 自动搭建的build 文件里没有dev-server.js 和 dev-client.js ,因此我们要在webpack.dev.conf.js 里配置
    配置如下:
    (1)复制data.json 到该项目下
    (2)找到bulid目录下 webpack.dev.conf.js 找到 const portfinder = require('portfinder'),在其下添加mock 数据

    // 添加mock 数据
    const express = require('express')
    const app = express()
    var appData = require('../data.json')//加载本地数据文件
    var seller=appData.seller;
    var goods=appData.goods;
    var ratings=appData.ratings;
    var apiRoutes = express.Router()
    app.use('/api', apiRoutes)

    (3)接着找到 devServer 里的 watchOptions,其后紧跟

    watchOptions: {
          poll: config.dev.poll,
        },
        before(app) {
          app.get('/api/seller', (req, res) => {
            res.json({
              errno: 0,
              data: seller
            })//接口返回json数据,上面配置的数据appData就赋值给data请求后调用
          }),
          app.get('/api/goods', (req, res) => {
            res.json({
              errno: 0,
              data: goods
            })
          }),
          app.get('/api/ratings', (req, res) => {
            res.json({
              errno: 0,
              data: ratings
            })
          })
        }

    (4)设置保存后 npm run dev 运行 访问http://localhost:8080/api/seller 就可接收到 该路由对应的json 数据

    三、关于路由 vue-router

    * 直接定义路由

    (1)首先定义路由

    //  定义路由组件
    	const goods = { template: '<p>我是对应的goods下面的内容</p>' };
    	const seller = { template: '<p>我是对应的seller下面的内容</p>' };

    (2)创建路由实例

    // 创建路由实例
    	var router = new VueRouter({
              routes:[
                //  路由重定向即设置默认路由  
                {path:'/',redirect:'/goods',component:goods}, 
                {path:'/goods',component:goods},
                {path:'/seller',component:seller}
              ]
          });

    路由实例方法:

    router.push({path:'goods'});  //直接添加一个路由,表现切换路由,本质往历史记录里面添加一个
    router.replace({path:'goods'}) //替换路由,不会往历史记录里面添加
    // router.go('goods')

    (3)创建vue 实例

    //  创建 vue 实例
    	const app=new Vue({
    		el:"#app",  //  挂载元素
    		router
    	})

    (4)DOM 渲染
    <body>
     <div id="app">
      <div class="nav">
       <router-link to='/goods'>good</router-link>
       <router-link to='/seller'>seller</router-link>
      </div>
      <div class="content">
       <router-view></router-view>
      </div>
     </div>
    </body>
    注意:

    查看效果时,发现动态的给当前路由 添加le一个router-link-active的类名,所以如果需要设置当前路由样式(比如:高亮)就可以直接在style里设置了

    * (main.js)引入路由组件

    (1)引入路由文件

    import goods from './components/goods/goods'
    import ratings from './components/ratings/ratings'
    import seller from './components/seller/seller'

    (2)创建路由实例 定义路由组件

    const router = new VueRouter({
      routes: [{
        path: '/',
        component: goods
      },{
        path: '/goods',
        component: goods
      }, {
        path: '/ratings',
        component: ratings
      }, {
        path: '/seller',
        component: seller
      }],
      linkActiveClass: 'active' //  将 router-link-active  改为 active(方便样式操作)
    })

    (3)创建vue实例并挂载

    new Vue({
      el:"#app",
      router,
      template: '<App/>',
      components: {
        App
      }
    })

    四、axios 请求数据

    (1)安装 axios
    npm install axios
    (2)引入axios组件

    import axios from 'axios'

    (3)axios 请求数据(在此之前创建一个接受数据的对sellerobj)

    export default {
     //  获取数据 准备  返回一个对象,后台获取数据后 赋予 该对象
       data (){
       	 return {
       	 	 sellerobj:{}
       	 }
       },
       created (){ //  创建之前 请求数据
       	 axios.get('static/data.json').then((result) => {
       	  	 console.log(result) //  控制台检查  数据存储在  result.data 里  
       	  	this.sellerobj = result.data.seller //  将数据存到sellerobj里  	 	
       	  })
       }
    }

    原文发布时间为:2018年01月19日
    原文作者:前端喵 

    本文来源:开源中国 如需转载请联系原作者





    展开全文
  • 一、vue版本2.9.6
  • 高仿Vue饿了么 实战开发

    千次阅读 2017-08-02 12:41:20
    简介这次我们使用 Vue 来完整的开发一个 App,下面展示了我们开发了一个 Web App 的全流程,从而让你真正的了解一个项目从零到一的过程:同时我们会以线上开发环境的要求来完成这次的开发任务,让你真正的了解一些...
  • 不过对于vue的入门还是不错的,使用的是vue1.0框架,虽然现在已经是vue2.0, 不过2.0基本上只是多了virtual-DOM,Templates || JSX || Hyperscript,流式服务端渲染及一些性能优化,并且管方也有详细的1.0到2.0的迁移...
  • vue2.0版,饿了么页面源代码.含2.0源代码以及开发笔记.基本会遇见的坑都已经在笔记中指出
  • vue饿了么

    千次阅读 2017-10-20 16:58:43
    项目一、Vue外卖AppMVVM架构:View ==== ViewModel ==== Model 视图 通讯 数据 DOM 观察者 Javascrip对象View和model通过 ViewModel来通信,但数据发生变化,Viewmodel能够观
  • 本原始代码基于GPL协议,仅用于Vue实战项目的学习,不可作为商业用途。 你可以学到什么 我们可以通过一张图来认识一下本课程的知识结构 如何学习 请从地面渠道购买本课程的教学视频: : 你还可以加入课程讨论群,与...
  • vue实战教程

    2019-03-27 16:03:57
    vue实战教程 1 前言 2 运用vue脚手架搭建开发环境 2 一, 什么是vue脚手架 2 二, 安装脚手架之前准备工作 3 安装node.js和npm 3 2, 安装vue-cli脚手架构建工具 4 三, 用vue-cli创建项目 4 四, 项目文件的介绍 9...
  • vue实战:vue.js高仿饿了么webapp

    千次阅读 2018-03-01 23:00:03
    学习了下mook的前端实战教程,花了几天时间看视频加上自己慢慢摸索,基本实现了全部的功能,因为教程中用的是vue1.0,而现在已经是2.0的版本,再加上2.0和1.0的差别还挺多的,所以很多地方也都是自己慢慢摸索出来了...
  • 初学vue时曾在网上搜索vue实战项目源码,无奈大部分都是简单的demo,对于深究vue没有太大的帮助,剩下的一些大部分都是像音乐播放器之类的展示型项目,交互没有预期那么复杂。但我们实际在工作中,经常会遇到有...
  • 第三篇-后端人员学习vue(项目实战) 教程地址:https://blog.csdn.net/m0_37499059/article/details/81328836
  • 适用人群Java开发人员,Vue开发人员,前后端分离开发人员,权限管理和配置开发人员 课程概述【讲师介绍】讲师职称:??????????????现某知名大型互联网公司资深架构师,技术总监,职业规划师,首席面试官,曾在某上市...
  • vue2.x饿了吗实战总结

    千次阅读 2018-02-26 07:10:26
    vue2.x仿饿了么app项目总结仿饿了么app是基于vue2.x最新实战项目,用到的技术栈vue2 + vue-router2 + vue-cli2+ axios + stylus + webpack2 + node.js 页面相对简单,所以没有用到vuex, 它更适合对复杂的单页面进行...
  • 1、熟悉了vue的项目开发流程 2、对动态组件、路由传参、vuex状态管理等都有了一定的熟悉 3、对sass有了一定的掌握 4、对mint UI有了一定的了解 5、进一步熟悉了移动端布局rem vw cacl() %   项目...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,266
精华内容 506
关键字:

饿了么vue实战

vue 订阅