vue仿饿了么项目

445 阅读2分钟

前言

苯宝宝写作本文的目的,是将开发过程中遇到的问题,涉及到的知识点,阅读过的好的文章记录下来,方便回顾和学习。

开发前的准备工作

dpr设备像素比

mock数据

【1】用nodejs启动一个本地服务

① 在webpack.dev.config.js中利用nodejs起一个本地服务,具体实现如下:

let express = require("express");
let app = express();
console.error(app)
let apiRoutes = express.Router();
let appDataGoods = require("../src/common/data/goods.json");
let appDataRatings = require("../src/common/data/ratings.json");
let appDataSellers = require("../src/common/data/seller.json");
apiRoutes.get("/seller", function (req, res) {
  res.json({
    error: 0,
    data: appDataSellers
  });
});
apiRoutes.get("/goods", function (req, res) {
  res.json({
    error: 0,
    data: appDataGoods
  });
});
apiRoutes.get("/ratings", function (req, res) {
  res.json({
    error: 0,
    data: appDataRatings
  });
});
app.use('/api', apiRoutes);
app.listen(3000); // 启动服务

② 配置proxy

proxyTable: {
  '/api': {
    target: 'http://localhost:3000',
  }
},

【2】请求本地静态mock数据

【3】使用json-server实现mock数据

【4】使用mock.js实现mock数据

express服务启动后不会自动停止

使用express启动的服务不会随着浏览器的关闭或者vue程序停止运行而关闭,这就导致了再次执行npm run dev的时候会报错,如下图:

解决:

① 查找pid

lsof -i:3000

② 关闭服务

kill -9 62406

报错:loaderContext.getResolve is not a function

经查证,为stylus-loader版本过高导致的

解决:安装稳定版本stylus-loader(3.0.2),至于版本号怎么找,点我

main.js中引入stylus报错

报错内容如下:

This relative module was not found:* ../src/common/stylus/index.styl in ./src/main.js

原因:新版本的vue-cli已经帮我们把less-loader配置好了,放在了util.js里面。但是我又在webpack.base.config.js中配置了

{
  test: /\.styl(us)?$/,
  loader: 'style-loader!css-loader!stylus-loader'
}

解决:删掉webpack.base.config.js中的配置

main.js中引入全局stylus不生效问题

上面的报错虽然解决了,但是苯宝宝发现,引入的样式并没有生效。。。😓。。真是忧伤啊!继续折腾吧!咸鱼。

这个问题真是不好解决。。。但是,终于还是找到了。在此,非常感谢贡献答案的大佬。

问题:直接在main.js中直接import进去,只有写死的样式会生效,定义的变量和函数,不生效。

可能的原因:引入时这个stylus文件就已经被编译成css文件并放在内联样式表里了,变量也被编译过了,所以在页面里再去使用,就找不到这个变量对应的值了。

解决方案:修改utils.js中的generateLoaders函数


function generateLoaders () {
   //...省略
   var stylusOptions = {
     import: [
        path.join(__dirname, "../src/common/base.styl"), // base.styl全局变量文件
     ]
   }
   return {
      css: generateLoaders(),
      postcss: generateLoaders(),
      less: generateLoaders('less'),
      sass: generateLoaders('sass', { indentedSyntax: true }),
      scss: generateLoaders('sass'),
      stylus: generateLoaders('stylus', stylusOptions), // 两项缺一不可
      styl: generateLoaders('stylus', stylusOptions) // 两项缺一不可
   }
  }
}

引入字体图标报错:This relative module was not found:./font/sell-icon.eot...

解决:将引入字体图标库的url改为url-loader

@font-face
  font-family: 'sell-icon'
  src: url-loader('../fonts/sell-icon.eot?k5xf13');
  src: url-loader('../fonts/sell-icon.eot?k5xf13#iefix') format('embedded-opentype'),
          url-loader('../fonts/sell-icon.ttf?k5xf13') format('truetype'),
          url-loader('../fonts/sell-icon.woff?k5xf13') format('woff'),
          url-loader('../fonts/sell-icon.svg?k5xf13#sell-icon') format('svg')

axios

安装

npm install axios

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

特性:

  • ✨从浏览器中创建XMLHttpRequests
  • node.js创建http请求
  • 支持Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

该部分涉及单点登陆等知识,将单独写一篇文章进行描述

axios用法这里不作赘述,写一下在全局使用axios的方法

axios 是一个基于 promise 的 HTTP 库,axios 并没有 install 方法,所以是不能使用 vue.use() 方法的。这就意味着,在 main.js 中直接 import axios 并不能使用。

解决方案:

  • 结合vue-axios使用
  • axios改写为Vue的原型属性
  • 结合Vuexaction

【1】结合vue-axios使用

第一步:在主入口文件main.js中引用

import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios,axios);

第二步:在组件中使用

getNewsList(){
  this.axios.get('api/getNewsList').then((response)=>{
     this.newsList=response.data.data;
  }).catch((response)=>{
     console.log(response);
  })
}

【2】axios改写为Vue的原型属性(不推荐)

第一步:在主入口文件main.js中引用,之后挂在vue的原型链上

import axios from 'axios'
Vue.prototype.$ajax= axios

第二步:在组件中使用

this.$ajax.get('api/getNewsList')
.then((response)=>{
    this.newsList=response.data.data;
}).catch((response)=>{
    console.log(response);
})

【3】结合Vuexaction

第一步:在vuex的仓库文件store.js中引用,使用action添加方法

import Vue from 'Vue'
import Vuex from 'vuex'

import axios from 'axios'

Vue.use(Vuex)
const store = new Vuex.Store({
  // 定义状态
  state: {
    user: {
      name: 'xiaoming'
    }
  },
  actions: {
    // 封装一个 ajax 方法
    login (context) {
      axios({
        method: 'post',
        url: '/user',
        data: context.state.user
      })
    }
  }
})

export default store

第二步:在组件中发送请求的时候,需要使用this.$store.dispatch

methods: {
  submitForm () {
    this.$store.dispatch('login')
  }
}

首页开发

嵌套路由 vs 动态路由

嵌套路由是子路由,动态路由是路由请求参数

移动端 1px 像素

【1】通过伪类给元素添加1px边框

border-1px($color)
  position: relative
  &:after
    display: block
    position: absolute
    left: 0
    bottom: 0
    width: 100%
    border-top: 1px solid $color
    content: ' '

【2】利用媒体查询进行缩放适配

@media (-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)
  .border-1px
    &::after
      -webkit-transform: scaleY(0.7)
      transform: scaleY(0.7)

@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2)
  .border-1px
    &::after
      -webkit-transform: scaleY(0.5)
      transform: scaleY(0.5)

参考文章: