Vue学习-饿了么项目练习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jplyue/article/details/82356951

抓数据

一、首先抓取主页列表数据:

  1. 研究一下主页的接口,需要传入经纬度和分页数据

  2. 通过fetch获取到数据后,重新定义一个对象,对应到数据库的设计结构

  3. 根据地址抓,利用writeFile取其中的图片到本地

  4. 将数据插入数据库

二、抓取列表项对应的详情页,包括餐馆介绍、菜单、购物车

流程同上,需要抓取菜单数据和食物数据

koa搭建后台

用到的插件们

const koa = require('koa');
const static = require('koa-static');//用于静态页面
const Router = require('koa-router');
const db = require('./libs/mysql');//mysql的操作集合
const pathlib = require('path');//文件路径
const config = require('./config');//所有配置信息(数据库配置)
const betterBody = require('koa-better-body');//用于form表单
const convert = require('koa-convert')//betterbody需要搭配convert使用
const session = require('koa-session')
const tokenSession = require('./libs/token-session')
betterBody

在获取post请求时,ctx中的request参数无法直接获取,需要通过betterBody中间件进行转换。betterBody是generator格式,通过koa-convert可以转换为promise使用。

支持text, buffer, json, json patch, json api, csp-report, multipart, form and urlencoded bodies

参数储存在这里:

扫描二维码关注公众号,回复: 3216560 查看本文章
console.log(this.request.files)
console.log(this.request.fields)

Github Link


1. 首先创建一个server,listen

const server = new koa();
server.listen(PORT);

2. form用到的中间件

注意,第二步和第三步的处理要放在router之前。

server.use(convert(betterBody()));

3. 对请求的处理和过滤,token处理

server.use(async (ctx, next) => {
  ctx.session = tokenSession();

  ctx.set({'Access-Control-Allow-Origin': '*'});
  ctx.set({'Access-Control-Allow-Headers': '*'});

  let token = ctx.request.headers['x-token'];

  await next();
});

4. Router

let router = new Router();
router.use('/api/', require('./routers/api.router'));
server.use(router.routes());

5. 静态页面处理

server.use(static(pathlib.resolve(__dirname, 'www/')));

api.router接口定义:

restaurant/:page/:size(get)分页获取餐馆的数据
restaurant/:id(get)获取某个餐馆的信息
cart/:item_id/:count (post)购物车物品的增加和更新
cart/:item_id(delete)购物车物品的删除
image/:id(get)获取图片
token(get)获取token
user/(post)注册
user/:username/:password(get)登录
verifyCode(get)获取验证码

Vue框架

下载 Vue-cli

vue init webpack 创建项目

一共涉及三个页面:主页(餐馆列表)、餐馆详情页、登录页

先去书写router

使用的Vue组件:

Vuex:组件间的状态管理

Vue.use(Vuex);

const store = new Vuex.Store({
  strict: true,
  state: {
    token: null,
    cur_user: null
  },
  mutations: {
    updateToken (state, arg) {
      if( !arg || arg.length != 32) {
        console.log(arg, '格式不对!');
      } else {
        state.token = arg;
      }
    },
    updateUser (state, arg) {
      state.cur_user = arg;
    }
  },
  actions: {
    updateToken ({commit}, arg) {
      commit('updateToken', arg);
    },
    updateUser ({commit}, arg) {
      commit('updateUser', arg);
    }
  },
  getters: {

  },
  modules: {
    user: User
  }
})

Axios

Vue.prototype.axios = axios.create({
  baseURL: 'http://localhost:8090/api/',
  timeout: 1000
});

Router

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'index',
      component: Index
    },
    {
      path: '/detail/:id/:menu',
      name: 'detail',
      component: Detail
    },
    {
      path: '/login/:type',
      name: 'login',
      component: Login
    }
  ]
})
涉及的Components

这里不详细描述,在实际操作的过程中,根据需要拆分。

遇到的问题

1. 初次加载列表页可能会报错,因为数据的还未完成获取,可以先使用v-if进行判断,有值再进行渲染
2. router的几种操作方法:
  • router.replace() 直接替换当前页,无法回退
  • router.push(); 向路由里添加一个路径。可以回退到这个页面
  • router.back(); 返回上一级页面(push进来的路由可以通过这里访问)
  • router.go(-3);指定返回上三级页面
3. 子组件的渲染交给子组件自己进行,无需从主组件进行数据传递,传对应的id即可
4. 选项卡的编写
//在data中储存一个数组
    titles: [{
        title: '点餐',
        type: 'menu'
      },{
        title: '评价',
        type: 'rate'
      },{
        title: '商家',
        type: 'info'
      }],
      curTab: 'menu'
    }
 //在html中v-for循环数组显示。点击显示的时候通过type进行判断。
5. filter

需要对返回的数据进行处理的,可以使用filter进行处理

<span>{{Math.round(restaurant.distance/60)|cn_time}}</span>

time_filter (time) {
     time = Number(time);
     return time<60?`${time}分钟`:`${time/60}小时${time%60}分钟`
}
6. 子组件接收父组件的属性传值:
props: [ 'restaurant' ]
7. 获取页面地址的参数:let {id} = this.$route.params;
8. token
//组件初始化的时候,先为用户生成一个token
async created () {
  if (localStorage.token) {
    this.$store.dispatch('updateToken', localStorage.token);
  } else {
    let token = (await this.axios.get('token')).data;
    localStorage.token = token;
  }
}

//token是储存在全局变量里进行传递的:
this.$store.state.token

//登录注册时候放在header里
if (this.$store.state.token) {
     headers['x-token'] = this.$store.state.token;
}
9. button disabled
<button type="submit" :disabled="btnDisabled"></button>

Vue中disabled的属性也可以通过data里的参数来控制。btnDisabled为true或false

10. loading…

可以利用mutation显示loading状态

mutations: {
    startLoading (state) {
      state.loading = true
    },
    endLoading (state) {
      state.loading = false
    },
}

actions: {
    async loadOnePageData ({state, commit}, arg) {
      commit('startLoading')
      commit('startLoadingMore')
      await sleep(3)
      let res = await (await fetch(`http://localhost:8082/list?page=${state.cur_page}`)).json()
      commit('endLoading')
      commit('endLoadingMore')
    },
},
11. getters用法

getters:对state 里面的数据二次处理,组件引用的时候可以直接去引用处理后的数据

getters: {
    list_data (state) {
      if (state.cur_page === 0) {
        store.dispatch('loadOnePageData')
      }
      return state.article_list
    }
  }

this.$store.getters.list_data
mapState、mapGetters
import { mapState } from 'vuex'

computed: {
    count(){
        return this.$store.state.count;
    },
    //还可以换种写法:
   ...mapState({
        count: state => state.count,
        // 传字符串参数 'count' 等同于 `state => state.count`
        countAlias: 'count',
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
    })
}

//在这种双方名字都一样的情况下,可以直接一步到位
computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

Reference Link

Getters就更简单了

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      doneCount: 'doneTodosCount'//起个名字
      // ...
    ])
  }
}

猜你喜欢

转载自blog.csdn.net/jplyue/article/details/82356951