低仿饿了么H5-纯前端Vue版 + 手把手教学

这是一个仿饿了么H5的前端练手,数据是伪造的。曾用vue1写过一个仿cnodeJs网站,在线预览:https://hbxywdk.github.io/vue-cnodeJs/#!/,半年过去,工作中很少有机会用上vue,vue也早已更新到2.+,想想学了不用也是白学了,这里仿个饿了么增加下熟练度。

代码地址:https://github.com/hbxywdk/eleme-vue2
预览点这里:https://hbxywdk.github.io/eleme-vue2-static/#/

网页是有假的账户密码的部分页面需要登录 ↓ ,最好在Chrome手机模式下浏览。
username:admin
password:admin

本地预览步骤

# clone 文件
git clone https://github.com/hbxywdk/eleme-vue2.git

# 进入 eleme-vue2 文件夹
cd eleme-vue2

# install dependencies
npm install

# 运行 npm run dev 会在浏览器打开 localhost:8080
npm run dev

如果你已经对vue很了解,那么看看预览就好不用继续阅读,如果你听说过vue,想学习一下,请继续看下去。

使用到的相关库或工具:vue2 + vuex2 + vue-router2 + vue-swipe + vue-cli

默认大家都已安装Node.js,且知道基础的ES6语法。

首先需要安装vue-cli,vue-cli是一个快速搭建vue项目的工具,就不需要我们一行一行写webpack配置了。

// 安装 vue-cli
npm install -g vue-cli

// 初始化一个项目
vue init webpack my-project

// 然后一路回车,记得勾选上vue-router
// 输入以下命令,等待浏览器打开
cd my-project
npm install
npm run dev

得到以下目录结构

-build
-config
-node_modules
-src            // 项目代码所在文件夹
-static         
-.babelrc
-.editorconfig
-.eslintignore
-.eslintrc.js
-.gitignore
-index.html
-package.json
-README.md

src为项目代码所在文件夹

手动添加vuex。(Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式)
npm install vuex -S
在src目录下创建store.js
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex) // 要记得use一下哦

export default new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    Count (state, platform) {
      state.count = platform
    }
  },
  actions: {
    setCount ({commit}, platform) {
      commit('Count', platform)
    }
  },
  getters: {
    getCount: (state) => state.count
  }
})

state为状态数据,触发action,mutations会去改变state的值,getters对外提拱state的值。

修改main.js。(main.js为webpack打包入口文件)
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './vuex/store'  // 引入store 

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store, // 注入store 
  template: '<App/>',
  components: { App }
})

加入store

修改App.vue
<template>
  <div id="app">
    ![](./assets/logo.png)
    {{ asd }}                                     // here
    <button @click="change(233)">变为233</button> // here
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app',
  computed: {                                           // here ↓
    asd () {
      return this.$store.getters.getCount
    }
  },
  methods: {
    change (arg) {
      this.$store.dispatch('setCount', arg)
    }
  }
}                                                       // here ↑
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

computed 写入 asd () {return this.$store.getters.getCount} ,通过vuex的getters就可得到state中的count,并在当前文件夹中以 asd 存在。
methods 中写入 this.$store.dispatch('setCount', arg), 执行change 方法会触发action ,改变count值为233,state值改变,computed 就会改变当前asd的值,template中也会相应改变。
更多vuex用法详见:https://vuex.vuejs.org/zh-cn/intro.html

Vue-router。(vue-router通常用于制作单页面应用,如其名就是给vue使用的路由,不清楚路由的可以百度一下)

在components文件夹中新建几个我们要用到的 .vue 文件,直接复制默认的Hello.vue文件即可,重命名并修改其中的不需要的内容。

修改router/index.js
import Vue from 'vue';
import Router from 'vue-router';
//  引入组件
import Homepage from 'components/Homepage';
import Order from 'components/Order';
import Myzone from 'components/Myzone';
import Business from 'components/Business';
import Login from 'components/Login';
import Search from 'components/Search';
Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'homepage',
      component: Homepage
    },
    {
      path: '/order',
      name: 'order',
      component: Order
    },
    {
      path: '/myzone',
      name: 'myzone',
      component: Myzone
    },
    {
      path: '/business/:id',
      name: 'business',
      component: Business
    },
    {
      path: '/search/:keyword',
      name: 'Search',
      component: Search
    },
    {
      path: '/login',
      name: 'Login',
      component: Login
    }
  ]
});

我们引入空白组件,并定义路由,当访问对应路径时,如localhost:8080/#/business,App.vue中的<router-view></router-view>就会展示对应内容,做到无刷新跳转。path: '/business/:id',后面的 :id 则是要传递的参数,组件中可以this.$route.params.id得到其值。

template中用<router-link>来跳转,<router-link> 默认会被渲染成一个 <a> 标签 <router-link to="/business/123">Go to Foo</router-link>,js中可用router.replace(location)来进行跳转。

更多用法详见http://router.vuejs.org/zh-cn/essentials/getting-started.html

下面进入到代码部分

整个项目使用 rem 方式布局,根据屏幕的宽度来自适应不同手机屏幕。
数据为伪造。
首页 Homepage.vue

// 部分代码
export default {
  mounted () {
    this.$store.dispatch('setLoading', true);// 设置当前状态为加载中,显示加载动画
    var time = Math.floor(Math.random() * 2000); // 模拟请求等待
    setTimeout(() => {
      this.$store.dispatch('setLoading', false); // 页面显示
      this.showMe = true;
    }, time);
  },
  computed: {
    ...mapGetters([
      'getLogin',
      'getFalseHotWord',
      'getFalseBussinessbrief' // 商家简略信息
    ])
  }
};

由于是纯前端页面,故使用setTimeout模拟下数据的加载,展示加载动画,computed中使用mapGetters来得到state中的数据,这样写与this.$store.getters.getCount实质上没有什么区别,但需要得到的数据较多时能少写不少代码。(使用前需引入)

导航部分使用 Vue-swipe 插件,https://github.com/ElemeFE/vue-swipe

商家列表部分,只有五个伪商家数据,加载更多的不断添加这五个伪数据。

Business.vue(商家详情页)
// 部分代码
export default {
  computed: {
    // 通过id找到store中对应店铺信息
    business_info () {
      return this.$store.getters.getFalseBussinessInfo[this.$route.params.id];
    }
  },
  methods: {
    // 右列表控制左列表样式
    rightControlLeftClass () {
       // code
    },
    // 左列表点击控制右列表滚动
    leftControlRightScroll (index) {
       // code
    },
    // 监控网页的resize来改变商品列表的高度
    watchHei () {
       // code
    },
    // 列表中的加按钮点击
    add_food (n, x, e) { // n 为大类 x为大类种商品
       // code
    },
    // 向购物车添加
    add_shopping_car (type, typename, foodname, foodid, foodprice) {
      if (!this.shoppingCarList[foodid]) {
        this.shoppingCarList[foodid] = {
          'type_accumulation': type,
          'type_name': typename,
          'name': foodname,
          'one_food_id': foodid,
          'unit_price': foodprice,
          'count': 1
        };
      } else {
        this.shoppingCarList[foodid].count++;
      }
      // 购物车改变 相关计算
      this.spChangeComputeAll();
    },
    // 购物车改变 相关计算
    spChangeComputeAll () {
       // code
    },
    // 结账
    checkout () {
       // code
    },
    // 添加商品抛球效果实现
    ball_fly (e) {
      // 每次添加获得点击按钮的坐标与目标位置的坐标,算得高度差值,并生成如下结构小球
      // <div class="father">
      //   <div class="child"></div>
      // </div>
      // father水平方向匀速运动,child垂直方向使用css3垂直上抛后再下降,即可得到抛球效果。
    },
  }
};

商家详情页占一整屏,最外层不允许出现滚动条,分上下两部分,上半部分给固定rem高度,下半部分高度动态计算,屏幕大小改变再次计算,下半部分,左右各一个ul列表,设置高度100%,overflow-y:auto;超出即可滚动。

左右列表
右ul滚动监控所有标题行的offsetTop,对比当前ul的scrollTop,给左ul添加对应样式。点击左列表,来控制右列表滚动。

购物车
data中定义一个购物车对象{ },添加某样商品时,已存在就+1,不存在则添加属性,每次添加计算总价等相关数据。

添加商品的抛球效果
每次添加获得点击按钮的坐标与目标位置的坐标,算得高度差值,利用初中物理,水平方向匀速运动,垂直方向垂直上抛运动,并添加向下的重力,即可得到抛球效果。

结算
结算时将当前购物车中计算出的简略信息添加到state中,清空购物车,跳转路由。

其他几个页面基本只是展示功能这里也就不再赘述。

如果想要更详细的内容,可以直接阅读代码,内有更详细的注释。

这个练习还有许多不够完善的地方,有机会的话我会完善这些不足。
如果可以的话顺手点个star,Thanks!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 兔 倌 1980年底,部队精简整编,每个连队要有三分之一的战士退伍,包括80年入伍的新...
    小五子_94ae阅读 1,269评论 1 3
  • 昨天在B 站看到一个视频。是几个女孩子讲述她们整容的经历的。片子不长,但是几个女生都讲了自己整容的原因。有的是觉得...
    谷雨写在四月后阅读 1,411评论 0 3
  • 红色历史知多少调查问卷 2017年7月7日肖静 雨后的空气格外清新,小红旗实践队来到紫荆山进行问卷调查。这是我的第...
    我想静静_24d6阅读 133评论 0 0