饿了么--vue项目总结
来迟了来迟了,早就应该动手写了,无奈卡在webpack的学习中,深陷泥潭。
github源码地址:饿了么项目源码
饿了么项目包含以下三个方面的技术点,以及所了解的知识。
1. 流程及开发方法:
- 组件化、模块化的开发模式
- 学会模拟json后端数据,前后端分离开发
- 了解webpack的打包原理
2. 第三方组件
- 学会使用vue-router开发单页应用
- 学会使用vue-resource与后端数据交互
- 学会如何在Vue.js框架里和第三方JS插件交互
3. 设计思想与模式
- 了解移动端设备像素比的概念
- 学会解决移动端1px边框问题
- 学会移动端经典的css sticky footer布局
- 学会flex弹性布局
第一个方面从webpack设置入手:
在build/webpack.base.conf.js文件下,可以看到基本的webpack设置(出入口文件位置,后缀补充以及别名等):
module.exports = {
context: path.resolve(__dirname, '../'),
// webpack编译的入口文件
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
// 生成的文件名字
filename: '[name].js',
// 请求的静态资源的绝对路径
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
// 自动补全文件后缀
extensions: ['.js', '.vue', '.json'],
// 别名,只针对于js库,css的引入还是要写相对路径,不能省略
alias: {
'@': resolve('src'),
// vue:'vue/dist/vue.js',
'components': path.resolve(__dirname, '../src/components'),
'common': path.resolve(__dirname, '../src/common'), //当在js文件中import其他文件时路径直接写commont相当于../src/common
}
},
然后在webpack.dev.conf.js文件中,设置了数据所在的位置,用于模拟后端数据的获取。
// 数据获取
var express = require('express') // express 是nodejs框架
var apiServer = express()
var bodyParser = require('body-parser')
apiServer.use(bodyParser.urlencoded({ extended: true }))
apiServer.use(bodyParser.json())
var apiRouter = express.Router()
var fs = require('fs')
apiRouter.route('/:apiName') //接口路径
.all(function (req, res) {
fs.readFile('./db.json', 'utf8', function (err, data) { //读取接口文件
if (err) throw err
var data = JSON.parse(data)
if (data[req.params.apiName]) {
res.json(data[req.params.apiName])
}
else {
res.send('no such api name')
}
})
})
// 数据所在的位置
apiServer.use('/api', apiRouter);
apiServer.listen(3000, function (err) {
if (err) {
console.log(err)
return
}
console.log('Listening at http://localhost:' + 3000 + '\n')
})
之后config/index.js目录下
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static', //被webpack编译处理过的资源文件都会在这个目录下
assetsPublicPath: '/', //根目录
proxyTable: { //解决跨域问题
'/api': 'http://localhost:3000/'
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false,
devtool: 'cheap-module-eval-source-map', //编译输出格式
},
}
webpack打包原理:
现象:假如说需要引入一大堆的js/css文件,且相互之间还存在引用关系,手动处理的时候就得按照一定的顺序。
解决:webpack将一大堆的文件都从一个入口引入,然后自动处理。(将模块的前后关系打包成一个js,指定js的单独打包等等),webpack实现模块化的管理。
功能:
1、根据模板生成html,并且自动处理上面的css/JS引用路径
2、自动处理img里图片路径,css样式中背景图的路径...字体引用
3、开启本地服务器,变写代码边自动更新页面内容
4、编译jsx、es6、sass、less、coffeescript等等并添加md5、sourcemap等辅助
5、异步加载内容,比如弹出框,不需要时不加载到dom
6、配合vue.js、react等框架开发等。
第二方面vue的主要文件设置:
根目录下的index.html设置viewport移动端视图,并且引入重置样式:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vueeleme</title>
<meta name="viewport" content="width=device-width,inital-scale=1.0,
maximum-scale=1.0,user-scalable=no"> // 这个meta标签使得页面宽度等于设备宽度,页面的缩放默认为1,且用户不能缩放。
<link rel="stylesheet" href="./static/css/reset.css"> //基础样式重置
</head>
<body>
<div id="app"></div> //挂载所需的id(在main.js中设置)
<!-- built files will be auto injected -->
</body>
</html>
main.js: 导入VueRouter 管理路由, 导入 VueResource实现数据交互。
///////main.js文件部分内容:
const routes = [ //设置路由及相应组件
{
path:'/',
redirect:"goods" //根目录下重定向到主页面
},
{
path:'/goods', //不同的路由使用不同的组件
component:goods
},
{
path:'/ratings',
component:ratings
},{
path:'/seller',
component:seller
}
]
const router = new VueRouter({ //将路由导入VueRouter
mode:'history', //可以去掉#
'linkActiveClass': 'active',
routes
})
const app = new Vue({ //渲染App.vue, 挂载到idnex.html中的#app中
router,
render: h => h(App)
}).$mount('#app')
App.vue 头部采用组件的形式,导航采用flex布局三等分,内容利用路由router-view进行显示。
<template>
<div>
<!-- 头部 -->
<v-header :seller="seller"></v-header> //组件化
<!-- 中部导航栏 -->
<div class="tab border-1px"> //flex三等分布局
<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>
第三方面设计思路:
设备像素比:devicePixelRatio,视觉稿是以iphone6的375×667屏幕屏幕高度作为基准,为了达到高清效果,视觉稿的画布大小会是基准的2倍。(对iphone6而言:原先的375×667,就会变成750×1334)。而在设计时候的数值为设计稿上的一半。
并且需要知道:1px 的 CSS 像素并不一定等于 1px 的物理像素,不同的设备会根据其对应设备像素比决定使用多少个物理像素显示 1px 的 CSS 像素。所以,在移动端不建议使用 px 作为布局单位,而是应该使用 rem 或者百分比作为布局单位。
参考链接:理解设备像素比
移动端1px边框: 利用伪类元素设置边框
border-1px($color)
position : relative
&:after
display: block
position: absolute
left: 0
bottom: 0
border-top 1px solid $color
width: 100%
content: ''
“Sticky Footer”: 指的就是一种网页效果: 如果页面内容不足够长时,页脚固定在浏览器窗口的底部;如果内容足够长时,页脚固定在页面的最底部。但如果网页内容不够长,置底的页脚就会保持在浏览器窗口底部。
参考链接: 各种CSS实现Sticky Footer
自适应布局:flex,两端的line自适应
html:
<div class="title">
<div class="line"></div>
<div class="text">优惠消息</div>
<div class="line"></div>
</div>
CSS:
.title
display: flex
margin: 28px auto 24px auto
width:80%
.line
flex:1
position:relative
top: -6px
border-bottom:1px solid rgba(255,255,255,.2)
.text
padding:0 12px
font-size:14px
font-weight:700