vue_eHungry 饿了么
eHungry 仿饿了么
- git 操作
git checkout -b dev // 创建新分支 dev
git push origin dev // 代码推送到 dev
------------------------------- 代码合并到主分支 ------------------------------
git checkout master
git merge dev
- 安装 stylus 依赖包
npm install stylus stylus-loader --save-dev
common/stylus/mixins.styl -------- 复用样式代码
$green = #02a774;
$yellow = #F5A100;
$bc = #e4e4e4; // 一像素下边框
bottom-border-1px($color)
position relative
border none
&:after
content ''
position absolute
left 0
bottom 0
width 100%
height 1px
background-color $color
transform scaleY(0.5) // 一像素上边框
top-border-1px($color)
position relative
&::before
content ''
position absolute
z-index 200
left 0
top 0
width 100%
height 1px
background-color $color //根据像素比缩放1px像素边框
@media only screen and (-webkit-device-pixel-ratio: 2 )
.border-1px
&::before
transform scaleY(.5) @media only screen and (-webkit-device-pixel-ratio: 3 )
.border-1px
&::before
transform scaleY(.333333) //根据像素比来使用 2x图 3x图
bg-image($url)
background-image: url($url + "@2x.png")
@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3)
background-image: url($url + "@3x.png") //清除浮动
clearFix()
*zoom 1
&::after
content ''
display block
clear both- 入口文件配置 main.js
import Vue from "vue"
import App from "./App.vue" new Vue({
el: "#app",
/*
components: {App},
template: "<App/>"
*/
/* 或者
render: function (createElement){createElement(App)}
*/
render: h=>h(App)
})- 路由器 router 配置 ---- 记得在 main.js 中加入 router
npm install vue-router --save
import Vue from "vue"
import App from "./App.vue" import Home from "../pages/Home"
import Search from "../pages/Search"
import Order from "../pages/Order"
import Personal from "../pages/Personal" Vue.use(VueRouter)
new VueRouter({
mode: "history", // 去掉 #
routes: [
{path: "/home", component: Home},
{path: "/search", component: Search},
{path: "/order", component: Order},
{path: "/personal", component: Personal},
{path: "/", redirect: "/home"}
]
})- 代理 /config/index.js ---- 改完配置要重启
dev:{
proxyTable: { // 更强大的代理
"api" :{ // 代理 /api 开头的请求
target: "http://localhost:5000", // 代理目标的基础路径
changeOrigin: true, // 支持跨域
pathRewrite: { // 重写路径: 去掉开头的 /api
"^/api": ""
}
},
"reqBaidu" :{ // 代理 /baidu 开头的请求
target: "http://localhost:5000", // 代理目标的基础路径
changeOrigin: true, // 支持跨域
pathRewrite: { // 重写路径: 去掉开头的 /baidu
"^/baidu": ""
}
}
}
}
- /src/api/ajax.js
import axios from "ajax"
export default function ajax(url, data={}, method="GET"){
return new Promise((resolve, reject)=>{
let promise = null
if(method==="GET"){
// params 指的是 query 请求字符串
promise = axios.get(url, {params: data})
}else if(method==="POST"){
promise = axios.post(url, data)
}
// promise.then(response=>resolve(response.data)).catch(err=>reject(err))
promise.then(response=>resolve(response.data)).catch(err=>alert(err)) // 外部无需多个 try catch 处理 reject
})
}
- /src/api/request.js -------- 参考接口文档,请求后台数据
import ajax from "./ajax"
// BASE = "http://localhost:5000"
const BASE = "/api" // proxTable 代理 /api 开头的请求
export function requestAddress(longitude, latitude){
// 根据 纬度,经度 获取店铺位置
return ajax(`/position/${longitude},${latitude}`);
}
export const requestCategory = ()=>ajax("/index_category"); // 获取商品分类
export const requestShops = (longitude, latitude)=>ajax("/shops", {latitude, longitude}); // 获取店
- Vuex.Store
npm install vuex --save
/src/vuex/store/index.js
import Vue from "vue";
import Vuex from "vuex"; import state from "./state"
import mutations from "./mutations"
import actions from "./actions"
import getters from "./getters" Vue.use(Vuex);
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
/src/vuex/store/state.js
export default {
isLoginRegister: false, longitude: "116.36867",
latitude: "40.10038", position: {},
categorysArr: [],
shops: []
}
/src/vuex/store/actions.js
import {
TOLOGINREGISTER,
SAVE_POSITION,
SAVE_CATEGORY,
SAVE_SHOPS
} from "./mutation-type" import {requestPosition, requestCategory, requestShops} from "../../api" export default {
toLoginRegister({commit}, to){
commit(TOLOGINREGISTER, to);
},
async getPosition({commit, state}){
const {longitude, latitude} = state
const result = await requestPosition(longitude, latitude)
if(result.code === 0){
commit(SAVE_POSITION, result.data)
}
},
async getCategorys({commit}){
const result = await requestCategory()
if(result.code === 0){
commit(SAVE_CATEGORY, result.data)
}
},
async getShops({commit, state}){
const {longitude, latitude} = state
const result = await requestShops(longitude, latitude)
if(result.code === 0){
commit(SAVE_SHOPS, result.data)
}
}
}
/src/vuex/store/mutations.js
import {
TOLOGINREGISTER,
SAVE_POSITION,
SAVE_CATEGORY,
SAVE_SHOPS
} from "./mutation-type" export default {
[TOLOGINREGISTER] (state, to) {
state.isLoginRegister = to
}, [SAVE_POSITION] (state, position) {
state.position = position
}, [SAVE_CATEGORY] (state, categorysArr) {
state.categorysArr = categorysArr
}, [SAVE_SHOPS] (state, shops) {
state.shops = shops
}
}
/src/vuex/store/mutations-type.js
export const TOLOGINREGISTER = "toLoginRegister" export const SAVE_POSITION = "save_position"
export const SAVE_CATEGORY = "save_category"
export const SAVE_SHOPS = "save_shops"
/src/vuex/store/getter.js
- 路由元信息 - 状态数据共享
/src/router/router.js
import Vue from "vue";
import VueRouter from "vue-router"; import Home from "../pages/Home/Home"
import Search from "../pages/Search/Search"
import Order from "../pages/Order/Order"
import Personal from "../pages/Personal/Personal"
import LoginRegister from "../pages/LoginRegister/LoginRegister" Vue.use(VueRouter);
export default new VueRouter({
mode: "history",
routes: [
{path:"/home", component: Home, meta:{showFooter: true}},
{path:"/search", component: Search, meta:{showFooter: true}},
{path:"/order", component: Order, meta:{showFooter: true}},
{path:"/personal", component: Personal, meta:{showFooter: true}}, {path:"/login_register", component: LoginRegister},
{path:"/", redirect: "/home"},
]
})- /src/App.vue
<template>
<div>
<router-view></router-view>
<FooterNav v-show="$route.meta.showFooter"></FooterNav>
</div>
</template>
...watch: {
categorysArr () {
// 在下次 DOM 更新后,再执行回调
this.$nextTick(()=>{
const mySwiper = new Swiper('.swiper-container', {
loop: true, // 循环模式选项
pagination: { // 如果需要分页器
el: '.swiper-pagination',
},
})
})
}
},
图片验证码点击,重新请求
改变 img 的 src,每次都必须赋新的值
this.$refs.captcha.src = "http://localhost:5000/captcha?curTime="+Data.now
Account SID
Auth Token
Rest URL 都一样
测试号码必须填
SMS 普通短信 sms_utilt.js 配置
MMS 彩信
-----------------------------------------------------------------------------------------
cookie 分两类
会话 cookie - 保存在浏览器运行时内存中,关闭浏览器后,数据清除 - 会话的标识
持久化 cookie - 保存在浏览器管理的文件中,关闭浏览器后,数据还在
session 会话 - 保存在服务器端,用于存储数据的容器 ---------- session 依赖于 cookie,浏览器可以禁用 cookie
会话: 浏览器的打开到关闭,整个过程是一个会话
session 对象保存在服务器存储数据的容器
一旦产生这个对象,服务器会自动向浏览器返回一个响应 cookie,用来保存 sessioin 的ID - connect.sid = sessionID
在服务器通过 request.session 获取到 session
session 如果有: 找到对应的 session 对象
session 如果不存在: 创建新的 session 对象
第一次登录,会将 user_id 存入 session
刷新浏览器, user_id 还是可以从 浏览器获取的
但是 session 通常与 cookie 进行连用
- 会话 cookie ---- 关闭浏览器,则数据清空
- 持久化 cookie ---- 关闭浏览器,数据还在
-------------------------------------------------------------------------------------
- mini-ui
npm install --save mint-ui
npm install --save-dev babel- // 实现按需打包
/src/mock/data.json
处理后台接口还不可使用的情况,拦截 ajax ,返回 模拟数据
/src/mock/mockServer.js -------- 使用 mockjs 来 mock 模拟数据接口
import Mock from "mockjs"
import data from "./data.json" -------- 内部会自动解析 JSON 对象 成 js 对象
// mock 三个接口,开始监视改变, 特别的是这个代码不会向外暴露什么
Mock.mock("/goods", {code: 0, data: data.goods})
Mock.mock("/ratings", {code: 0, data: data.ratings})
Mock.mock("/info", {code: 0, data: data.info})
/src/main.js
import "./mock/mockServer" // 保证 mockjs 被打包执行,从而组件可以使用
4
4
- Vuex.Store 模块化
管理的状态
{home:???, user:???, shop:???}
/vuex/store/modules/
home.js
- 1
/src/vuex/store/index.js
import home from "./modules/home"
import user from "./modules/user"
import shop from "./modules/shop"
export default new Vuex.Store({
modules: {
home,
user,
shop
}
})
npm install --save better-scroll
new BScroll(".wrapper", {})
mounted () {
this.$nextTick(()=>{
if(!this.bScroll){
this.bScroll = new BScroll(".header_nav", {
click: true,
scrollX: true
})
}else{
this.bScroll.refresh()
}
})
}- ...mapGetter(["xxx"])
模块化 时,无论写在模块内还是公共 getter,都是一样的,
只是在编写 getter 时,注意不能重名,和 state 的指向
- 单例对象
某种类型的实例对象只存在一个
在轮播图 逻辑的元素,在控制外层元素时,只能用 v-show 而不能用 v-if
- moment 自定义过滤器 - 日期处理 /src/filters/index.js
import Vue from 'vue'
import moment from "moment"
Vue.filter('data-format', funtion(vue, formatStr="YYYY-MM-DD HH:mm:ss"){
return moment().format(formatStr)
})
- 优化 router ---- 路由懒加载效果
1. 使用 import 函数: 被引入的模块单独打包 (生成有一个单独的一个 js 文件)
2. 配置的 component 是“返回 import() 得到的模块的函数”, 只有当请求对应的 path 才会执行函数,得到组件
- 图片懒加载 vue-lazyload ---- 其实 mint-ui 内置了这个库
- main.js
---- 内部会指定一个指令 lazy
- 在组件中 <img v-lazy="food.image"/>
- 构建打包app
1. 无 # 哈希路由 ---- 配置 404 页面, 将 404 页面指向 目标页面 index.html ---- 单页面应用
在页面刷新,就会向后台请求路由,而路由是前台路由
将服务器进行 中间件拦截 - 将前台路由请求 返回 public 页面
2. 使用 /#/ 哈希路由 ---- 始终会被当成前台路由处理,而不会当成后台路由处理
- 将 store 保存到 Vue 上 ---- 很实用
- 导航守卫
是 vue-router 提供的 下面 2 个方面的功能
- 监视路由跳转
- 控制路由跳转
应用
在跳转到界面之前,对用户进行检查限制
在界面离开之前进行收尾工作
分类
全局守卫 ---- 针对任意路由跳转
/src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router"; // import Home from "../pages/Home/Home"
import Shop from "../pages/Shop/Shop"
import Goods from "../pages/Shop/Goods/Goods"
import Ratings from "../pages/Shop/Ratings/Ratings"
import Info from "../pages/Shop/Info/Info" // import Search from "../pages/Search/Search"
// import Order from "../pages/Order/Order"
// import Personal from "../pages/Personal/Personal"
import LoginRegister from "../pages/LoginRegister/LoginRegister" const Home = ()=>import("../pages/Home/Home")
const Search = ()=>import("../pages/Search/Search")
const Order = ()=>import("../pages/Order/Order")
const Personal = ()=>import("../pages/Personal/Personal") Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
routes: [
{path:"/home", component: Home, meta:{showFooter: true}},
{
path:"/shop",
component: Shop,
children: [
{path:"/shop/goods", component: Goods},
{path:"/shop/ratings", component: Ratings},
{path:"/shop/info", component: Info},
{path:"/shop", redirect: "/shop/goods"},
]
}, {path:"/search", component: Search, meta:{showFooter: true}},
{path:"/order", component: Order, meta:{showFooter: true}},
{path:"/personal", component: Personal, meta:{showFooter: true}}, {path:"/login_register", component: LoginRegister}, {path:"/", redirect: "/home"},
]
}) /*************************************************/
const paths = ["/login_register"]
router.beforeEach((to, from, next)=>{ // 设置全局守卫
const path = to.path
if(paths.indexOf(path)>=0){
if(Vue.store.state.user.userInfo._id){ // 在 main.js 中保存 store
return next("/personal")
}
}
next() // 其他路由请求,放行
})
/*************************************************/ export default router- 全局前置守卫: 在准备跳转到某个路由组件之前 (在开发中用的较多)
router.beforeEach((to, from, next)=>{
})
to ---- 目标路由
from ---- 当前路由
next ---- 函数
next() ---- 执行下一个守卫回调,如果没有,就跳转到目标路由
next(false) ---- 不继续执行,跳转流程在此处中断,不会跳转到目标路由组件
next(path) ---- 跳转到指定的另一个路由
next() ---- 传入的回调函数会在组件对象创建后对象,即延后执行回调 - 且将组件对象传入回调函数 即 this
- 全局后置守卫: 在跳转到某个路由组件之后
router.afterEach((to, from)=>{
})
组件守卫 ----
beforeRouteEner(){ // 在跳转到当前组件之前,无法访问这个组件的组件对象 this
}
beforeRouteUpdate(){ // 在当前组件显示更新前调用,可以访问 this
}
beforeRouteLeave(){ // 在当前组件离开前调用,可以访问 this
}
- 构建打包
- 配置前台路由 - 404 页面
/src/router/index.js
在数组最后,配置{path: "/*", NotFound}
vue_eHungry 饿了么的更多相关文章
- 解析ListView联动的实现--仿饿了么点餐界面
一.博客的由来 大神王丰蛋哥 之前一篇博客仿饿了点餐界面2个ListView联动(http://www.cnblogs.com/wangfengdange/p/5886064.html) 主要实现了2 ...
- IOS-小项目(饿了么 网络部分 简单实现)
在介绍小项目之前,在此说明一下此代码并非本人所写,我只是随笔的整理者. 在介绍之前先展现一下效果图. 看过效果图大家应该很熟悉了,就是饿了么的一个界面而已,值得注意的是,实现时并没有采用本地连接,而是 ...
- 饿了么基于Vue2.0的通用组件开发之路(分享会记录)
Element:一套通用组件库的开发之路 Element 是由饿了么UED设计.饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库.今天我们要分享的就是开发 Element 的一些心得. 官网 ...
- 用vue2 +vue-router2 + es6 +webpack 高仿饿了么app(干货满满)
#高仿饿了么app商家详情 (vue2 +vue-router2 + es6 +webpack ) ##demo [demo 地址](http://liangxiaojuan.github.io/ ...
- java中的单例模式(懒汉式+饿汉式)
什么是单例模式: 单例模式既只能在自己本类中创建有且唯一的一个实例(姑且不考虑映射的情况)通过方法将该实例对外公开 第一种:单例模式-懒汉式 既调用getInstance()方法返回实例之前判断有没有 ...
- 仿饿了点餐界面2个ListView联动
如图是效果图 是仿饿了的点餐界面 1.点击左侧的ListView,通过在在适配器中设置Item来改变颜色,再通过notifyDataSetInvalidated来刷新并用lv_home.setSele ...
- C++的单例模式与线程安全单例模式(懒汉/饿汉)
1 教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实 ...
- 这交互炸了:饿了么是怎么让Image变成详情页的
这交互炸了:饿了么是怎么让Image变成详情页的 晚上叫外卖,打开饿了么,发现推了一个版本,更新以后,点开了个鸡腿,哇,交互炫炸了. 本文同步自wing的地方酒馆 不过还是有槽点.我是无意中才发现可以 ...
- (转)Singleton 单例模式(懒汉方式和饿汉方式)
原文地址:http://www.cnblogs.com/kkgreen/archive/2011/09/05/2166868.html 单例模式的概念: 单例模式的意思就是只有一个实例.单例模式确保某 ...
随机推荐
- [物理学与PDEs]第1章第7节 媒质中的 Maxwell 方程组 7.3 媒质中电磁场量的表示
1. 电磁能量密度 $$\bex \cfrac{1}{2}({\bf E}\cdot{\bf D}+{\bf B}\cdot{\bf H}). \eex$$ 2. 电磁能量流密度向量 $$\bex { ...
- sqlserver 获取所有表的字段类型等信息
USE [MultipleAnalysisDataFY] GO /****** Object: View [dbo].[selectfieldtype] Script Date: 2018/11/7 ...
- Django2.1配置xadmin2.0
系统:Ubuntu18.04 环境:py3.6, django2.17, xadmin-django2.0 xadmin-django2.0下载:xadmin2.0(进入github后,在Branch ...
- 移动端click事件300ms延迟
移动端click 事件延迟300ms 一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟.也就是说,当我们点击页面的时候移动端浏览器并不是立即作出反应, ...
- 基于scrapy-redis分布式爬虫的部署
redis分布式部署 1.scrapy框架是否可以自己实现分布式? - 不可以.原因有二. 其一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls ...
- Easyui datalist 使用记录
仅简单记录下,资料相对比较少 官方给了一个很简单的例子,没啥用处,文档:http://www.jeasyui.com/documentation/datalist.php 学习要点: 1.追加行 $( ...
- [Ynoi2018]末日时在做什么?有没有空?可以来拯救吗?
这道题真的超级...毒瘤 + 卡常 + 耗 RP 啊... 传送门 noteskey 题解看 shadowice 大仙 的 code 如果发现自己 T 掉了,别心急,洗把脸再交一遍试试... //by ...
- Unable to find header files
在本模块导出头文件时,可以使用如下方式: LOCAL_EXPORT_C_INCLUDE_DIRS := $(MY_DIRECTORY_PATH) LOCAL_EXPORT_C_INCLUDES := ...
- spring+redis的集成,使用spring-data-redis来集成
1.参考:https://www.cnblogs.com/qlqwjy/p/8562703.html 2.首先创建一个maven项目.然后加入依赖的jar包就行了.我加入的jar包很多,反正加入了也没 ...
- ios 在工程中使用字体
1.将字体拖入项目 2.在info.plist 文件中加入 3.使用 self.label.font = [UIFont fontWithName: @"FZ XingHei" s ...