美文网首页js css html
越写悦快乐之Vue项目如何使用JSON Server快速生成Mo

越写悦快乐之Vue项目如何使用JSON Server快速生成Mo

作者: 韬声依旧在路上 | 来源:发表于2019-05-21 14:45 被阅读0次
JSON Server - 图片来自简书App

今天的越写悦快乐系列文章为大家带来Vue项目如何使用JSON Server快速生成Mock数据,做过前端开发的小伙伴都知道,Vue在前端圈的流行程度,它可以快速构建响应式的Web页面,配置数据驱动的方式来操作虚拟DOM,构建易用、灵活、高效的Web页面。今天的文章我为大家介绍一下如何使用JSON Server快速构建Mock数据,利用Express路由转发客户端请求,然后返回响应数据给Vue组件,Vue组件通过比对虚拟DOM并计算变更来更新页面,最后把更新结果渲染在页面上。

开发环境

  • Window 10.0.17763
  • Node 10.15.3
  • Yarn 1.16.0
  • Vue CLI 3.7.0
  • Git 2.21.0

基本原理

基本原理 - 图片来自简书App
  • 启动开发服务器
  • 通过Mock服务器代理页面发送的请求
  • Mock服务器根据路由解析请求并返回数据
  • 数据返回后交由Vue组件(Single File Components)来处理并渲染
  • 渲染完成后显示在页面

Vue Page是一个SFC,也可以包含多个Component。

挂载App的含义是将创建Vue对象与某个DOM节点(也就是HTML中的标签)进行绑定。

安装

  • npm方式

npm install -g json-server

  • yarn方式

yarn global add json-server

  • pnpm方式

pnpm install -g json-server

配置代理

我们在vue.config.js文件中添加devServer

module.exports = {
  lintOnSave: false,
  devServer: {
    proxy: 'http://localhost:3000/'
  },
  css: {
    sourceMap: true
  }
};

生成Mock数据

我们在项目目录下创建__mock__目录并创建faker.js文件,其文件内容如下。

module.exports = function () {
    var faker = require("faker");
    faker.locale = "zh_CN";
    var _ = require("lodash");
    return {
        people: _.times(100, function (n) {
            return {
                id: n,
                name: faker.name.findName(),
                avatar: faker.internet.avatar()
            }
        }),
        address: _.times(100, function (n) {
            return {
                id: faker.random.uuid(),
                city: faker.address.city(),
                county: faker.address.county()
            }
        })
    }
}

我们可以通过 json-server __mock__/faker.js启动服务,此时默认监听的端口是3000,接下来在浏览器地址栏输入http://localhost:3000/address查看返回的数据

配置运行脚本

要通过yarn运行脚本,需要在package.json文件中的scripts中添加

{
  "name": "vant-tour",
  "version": "1.0.0",
  "private": true,
  "description": "An Vant Tour",
  "license": "MIT",
  "author": "Watony Weng <softweitao@126.com>",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
+   "mock": "json-server --watch __mock__/faker.js"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "vant": "^1.6.14",
    "vue": "^2.6.10",
    "vue-router": "^3.0.5"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.4.0",
    "@vue/cli-plugin-eslint": "^3.4.0",
    "@vue/cli-service": "^3.4.0",
    "babel-plugin-import": "^1.8.0",
    "faker": "^4.1.0",
    "less": "^3.8.1",
    "less-loader": "^4.1.0",
    "postcss-pxtorem": "^4.0.1",
    "vue-cli-plugin-axios": "0.0.4",
    "vue-template-compiler": "^2.6.10"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/recommended"
    ],
    "rules": {},
    "parserOptions": {
      "parser": "babel-eslint"
    }
  },
  "browserslist": [
    "Android >= 4.0",
    "iOS >= 7"
  ]
}

验证

有这样一个场景,需要一个地址列表并且可以模糊搜索,那么我们可以这样操作,先给出示例例页面的截图。

页面截图 - 图片来自简书App

创建单文件组件(SFC)

创建src/views/home/index.vue文件,下面给出这个文件的示例。

<template>
  <div>
    <van-nav-bar :title="pageTitle"/>
    <van-search 
      v-model="value" 
      placeholder="请输入搜索关键词" 
      show-action 
      @search="onSearch">
      <div 
        slot="action" 
        @click="onSearch">搜索</div>
    </van-search>
    <van-list 
      v-model="loading" 
      :finished="finished" 
      finished-text="我是有底线的" 
      @load="onLoad">
      <van-cell
        v-for="(item, index) in list"
        :key="item"
        :title="item"
        @click.native="onClickItem(index)"
      />
    </van-list>
  </div>
</template>

<script>
import { Cell, List, NavBar, Toast, Search } from 'vant'

export default {
  name: 'Home',
  components: {
    [Cell.name]: Cell,
    [List.name]: List,
    [NavBar.name]: NavBar,
    [Toast.name]: Toast,
    [Search.name]: Search
  },
  data() {
    return {
      pageTitle: '地址列表',
      value: '',
      url: '',
      loading: false,
      finished: false,
      list: [],
      items: null
    }
  },
  watch: {
    value(newVal, oldVal) {
      if (newVal.length == 0) {
        this.items = null
        this.list = []
        this.onLoad()
      }
    }
  },
  methods: {
    onLoad() {
      this.loading = false
      this.url = 'address'
      this.axios
        .get(
          this.url,
          {},
          {
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            }
          }
        )
        .then(result => {
          const data = result.data
          if (data.length <= 0) {
            Toast.fail('暂无数据')
          } else {
            this.items = data
            for (var i = 0; i < data.length; i++) {
              this.list.push(data[i].city)
            }
            this.finished = true
          }
        })
    },
    onClickItem(index) {
      console.log('onClickItem ' + JSON.stringify(this.items[index]))
    },
    onSearch() {
      if (this.value.length == 0) {
        Toast.fail('关键词去哪了')
        return
      }
      this.url = 'address?q=' + this.value
      this.axios
        .get(
          this.url,
          {},
          {
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            }
          }
        )
        .then(result => {
          const data = result.data
          this.items = null
          this.list = []

          if (data.length <= 0) {
            Toast.fail('暂无数据')
          } else {
            this.items = data
            for (var i = 0; i < data.length; i++) {
              this.list.push(data[i].city)
            }
            this.finished = true
          }
        })
    }
  }
}
</script>
<style lang="less">
</style>

配置路由

我们在路由文件src/router.js中添加Home组件的声明。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const routes = [
  {
    path: '*',
    redirect: '/home'
  },
  {
    name: 'home',
    component: () => import('./views/home'),
    meta: {
      title: '手机端'
    }
  }
]

routes.forEach(route => {
  route.path = route.path || '/' + (route.name || '')
})

const router = new Router({ routes })

router.beforeEach((to, from, next) => {
  const title = to.meta && to.meta.title
  if (title) {
    document.title = title
  }
  next()
})

export { router }

配置插件

我们使用Axios来发送请求,此时我们需添加插件vue-cli-plugin-axios,通过这个插件会自动添加axios依赖并且在src/plugins下生成axios.js文件,其文件内容如下。

'use strict'

import Vue from 'vue'
import axios from 'axios'

axios.defaults.headers.get['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded; charset=UTF-8'

let config = {
  timeout: 60 * 1000,
  responseType: 'json'
}

axios.defaults.transformRequest = [
  function(data) {
    let ret = ''
    for (let it in data) {
      ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
    }
    return ret
  }
]

const _axios = axios.create(config)

_axios.interceptors.request.use(
  function(config) {
    return config
  },
  function(error) {
    return Promise.reject(error)
  }
)

_axios.interceptors.response.use(
  function(response) {
    return response
  },
  function(error) {
    return Promise.reject(error)
  }
)

Plugin.install = function(Vue, options) {
  Vue.axios = _axios
  window.axios = _axios
  Object.defineProperties(Vue.prototype, {
    axios: {
      get() {
        return _axios
      }
    },
    $axios: {
      get() {
        return _axios
      }
    }
  })
}

Vue.use(Plugin)

export default Plugin

启动

  • 启动代理服务

yarn mock

启动代理服务 - 图片来自简书App
  • 启动应用

yarn serve

启动服务 - 图片来自简书App
  • 打开浏览器输入http://localhost:8080/即可看到列表页面
欢迎来到Vue的世界 - 图片来自简书App

参考

示例

个人总结

总结一下今天分享的内容,我们从Vue CLI出发,使用有赞的Vant搭建了一个手机端的页面,该页面使用List组件进行渲染,数据来源自JSON Server生成的模拟数据,随后我们添加了搜索组件并监听输入框的值将搜索结果实时显示在列表项中,那么对于项目中使用的工具、库和框架,我们需要有一个更加感性的认识,Vue框架是如何渲染页面的,页面的数据从何而来,如何发起请求,组件中如何调用axios这些知识点在实践的过程中会有一个不一样的认识,当然也需要我们了解前端发展的新趋势,在移动互联网的后时代如何把握和利用小程序的红利构建不一样的产品形态,创建不一样的用户价值,构建属于我们的新时代,我相信这仅仅是开始,我们一直在路上,期待遇见更好的自己,期待和大家一起成长,也希望大家保持学习的热情,继续努力,成就非凡梦想。若是我的文章对你有所启发,那将是我莫大的荣幸。

相关文章

网友评论

    本文标题:越写悦快乐之Vue项目如何使用JSON Server快速生成Mo

    本文链接:https://www.haomeiwen.com/subject/vpqjzqtx.html