vue项目实践@树洞(二)

书接上文

上一篇粗略地搭建了项目,运行一下,编译经过,可是控制台上打出一个红色错误警告!报错了?!什么状况,还没作事就错了,来看看什么错!javascript

'Locale' is defined but never used,就是说Locale这个变量没有使用。在引入UI组件库的时候,个人编辑器已经错误提示了,莫名其妙嘛。并不是这个错抛得莫名其妙,而是这个错不是本身形成的。设想一下,在插件的基础上加了很复杂的逻辑,这时来一个这样莫名其妙的错,是否是很无语。这只是一个假想,绝大多数状况不会是插件带来的。不过,我仍是选择本身撸代码,不去使用所谓的插件,除非使用例如Babel之类的工具。css

除此以外,使用ESLint还会有更多的错误提示。好比,配置postcss.config.js的时候也会给出错误警告,我在上一篇文章给的配置文件的key使用的是双引号,它会提示使用单引号。再好比,ES推荐使用箭头函数,在某些时候没用使用箭头函数也会跑错,特别是使用插件。代码提示会抛出不少语法上的错误提示,若是开了ESLint,那就按着它的提示来培养代码编写习惯吧。html

// 从新给一下postcss.config.js
module.exports = {
  plugins: {
    'postcss-import': {},
    'postcss-url': {},
    'postcss-aspect-ratio-mini': {},
    'postcss-write-svg': {
      uft8: false
    },
    'postcss-cssnext': {},
    'postcss-px-to-viewport': {
      viewportWidth: 375,
      unitPrecision: 3,
      viewportUnit: 'vw',
      selectorBlackList: ['.ignore', '.hairlines'],
      minPixelValue: 1,
      mediaQuery: false
    },
    'postcss-viewport-units': {
      'silence': true
    },
    'cssnano': {
      preset: 'advanced',
      autoprefixer: false,
      'postcss-zindex': false
    }
  }
}

我不喜欢ESLint之类的语法错误提示,我记得最搞笑的一次,个人编辑器设置的4个空格格式化代码。当时使用的webstorm编辑器,它能够给开发者提供了vue模版,而后生成的代码也是4个空格的规则。但是当我运行代码的时候就抛错了,它要求使用的2个空格,排查了好久才发现。我就在想,若是说相似变量声明没有使用之类的错误抛出是能够接受的,像这2个空格之类的抛错真的有必要吗?固然,这类工具能够本身配置,只是感受默认值很瓜。前端

看下页面,先看下PC下的显示,全部元素的间距大小都很大。切换到iphone 6的环境下,这时就是正常的间距。上面配置的375一倍像素,这时默认的设计。vw是根据浏览器视口宽度进行计算的单位,在pc环境下,浏览器视口变大全部元素也会随着发生变化。LOGO没有设置大小,因此一直保持这个尺寸。vue

试着改变浏览器大小,这时这些元素也会随之变化,这样就无需JS去监听resize事件。这时它的好处,也算得上是缺点:它是根据视窗发生变化的,因此移动端和PC端必须分开。使用rem能够设置一个峰值,当监听到视窗宽度达到峰值就按一倍像素展现再也不缩放,vw则不能。java

小到iPhone 5,大到iPad,效果都还不错,能够下一步了。node

网络请求

## 拦截封装 ##ios

网络请求是一个必然,我准备使用axios,这个库使用的ES6语法,就很棒。git

# 安装axios
npm i -D axios

在src下新建一个apis的目录,作一个简单的拦截封装。这个封装我在别的项目用过,数据请求都没问题,因为这个项目缺乏后端接口的环节,所以暂且只是一个普通的封装。web

// 封装拦截 http.js
import axios from 'axios'

// 默认参数根据状况配置
// 接口地址环境变量 process.env.VUE_APP_HOST
axios.defaults.baseURL = process.env.VUE_APP_HOST
axios.defaults.timeout = 10000
axios.defaults['Content-type'] = 'application/json;charset=UTF-8'

axios.interceptors.request.use(config => {
  // 参数处理
  return config
}, error => {
  return Promise.reject(error)
})

axios.interceptors.response.use(response => {
  // 响应处理
  return response
}, error => {
  // 错误处理
  return Promise.reject(error)
})

// 请求封装
export function request(url, method = 'get', params = {}) {
  params = /(get)|(delete)|(head)/ig.test(method) ? { params } : params
  return axios[method](url, params)
}

export default axios
// 具体接口文件 api.js
// 能够根据业务需求分模块编写,按需引入
import { request } from './http'

export const getImgCode = params => request('/utils/public/yzm/get', 'post', params)

按照个人作法,在http.js拦截的时候会统一进行错误处理。为了防止屡次点击按钮触发请求,会在请求开始使用模态loading防止屡次触发请求。我并无彻底拦截错误,封装保持错误的返回,由于有时须要在错误里作后续操做。Promise在catch以后再将同一个错误抛出,在最后还须要catch一次。

暂且作这样的封装,在开始作接口以后,这个封装会改成async/await语法来封装,整个封装结构再从新考虑,这是后话。

## 跨域请求 ##

接口开发和前端开发所在的网络必然会形成跨域问题,这个问题能够经过服务器容许跨域来处理。此外,还能够经过本地的代理来处理这个问题,配置一下vue.config.js。

devServer: {
  proxy: {
    "/api": {
      target: process.env.VUE_APP_PROXY,
      changeOrigin: true,
      ws: true,
      pathRewrite: {
        "^/api": ''
      }
    }
  }
}

接口地址被代理,那么http.js中的baseURL对应的地址是/api。一般码好http.js、vue.config.js这类文件,在其余项目中几乎能够直接使用,因此,我将这两个文件对应的地址改成了环境变量process.env.VUE_APP_HOST、process.env.VUE_APP_PROXY,之后只需修改环境变量就能够了。

在项目根目录,新建三个文件,它们分别表明三个环境,development、production是vue默认的开发环境和生产环境。事实上,至少还须要一个环境,测试版的生产环境。总不可能在本地开发完了就直接打包进生产环境,因而须要先打包上测试服务器,测试完成再部署生产环境。这个环境我用的debug来标识,三个文件分别是:.env.development、.env.production和.env.debug。值得一提的是:这个文件是按文本读取,它的值是字符串类型。

NODE_ENV=development
VUE_APP_HOST=/api
NODE_ENV=production
VUE_APP_HOST=https://www.production.com
NODE_ENV=production
VUE_APP_HOST=https://www.debug.com

关于环境变量官方文档说得很详细,我就不作赘述。环境变量配置好了,给测试服务器打包,还须要在package.json里面增长一个脚本。由于它和build执行的是同一编译环境,增长一个参数就行了:

"debug": "vue-cli-service build --mode debug"

这个debug环境能够增长一些其余处理,好比打包的时候分析包的占比,这在后面打包的时候会提到。

前期工做

## 样式重置 ##

在开始页面编写以前咱们一般须要重置html元素的默认样式。为了统同样式,还须要申明一些变量来进行控制颜色、字体大小等等,这是全局的。更多的样式是精确到组件,可是主体的标准是来自全局,从而造成本身的UI库。除此以外还会有公共样式,好比1px边线的处理,文字溢出处理等等。

在技术选型的时候,我没有提到动态语言的选择,用哪一种语言并不影响最后的代码。这部分无需多言,根据本身的喜爱进行就行了。

## svg图标 ##

我不主张使用字体图标,这是一个庞大的资源。我在首页引入了vant的tabbar组件,5个图标,有时会出现方格状态(资源未加载完的状况)。字体图标最大的好处,我认为就是它能像字体同样进行大小控制,有得必有失嘛。为了图标在放大缩小的时候不失真,我选择使用字体图标。

做为图标必然会在不少地方使用,因此在components编写一个组件SvgIcon.vue。

<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"/>
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      return `svg-icon ${this.className}`
    }
  }
}
</script>

<style scoped lang="scss">
.svg-icon {
  display: block;
  min-width: 1em;
  fill: currentColor;
  overflow: hidden;
}
</style>

这个组件有两个属性:svg的名字及样式名。样式.svg-icon的fill目的是让svg图标颜色与字体颜色一致,属性里的样式名用于组件自定义样式。值得注意的是,svg文件源码写有fill属性且有颜色值没法修改图标颜色,须要去掉这个属性,或者修改fill=“currentColor” ,或者修改fill=""。

在src下新建一个目录icons,再在这个目录下新建一个目录svg和index.js文件。svg目录存放svg文件,index.js用于加载全部的svg。这不是必要的,能够按需引入SvgIcon组件便可。

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'

Vue.component('svg-icon', SvgIcon)

const create = ctx => ctx.keys().map(ctx)
create(require.context('./svg', false, /\.svg$/))

在main.js中引入icons。若是package.js中没有配置入口文件,默认是index这个文件,所以直接引入目录icons便可;若是配置有入口文件,那么编译时会先去找这个文件。写全路径自己确定不会有问题。

import '@/icons'

vue内部本来是有svg这个规则,它不太能知足需求,改用svg-sprite-loader。

# 安装svg-sprite-loader
npm i --save-dev svg-sprite-loader

在vue.config.js中进行相关配置:

// 引入path
const path = require('path')

// 修改chainWebpack
chainWebpack: config => {
  // 清除默认svg规则改成svg-sprite-loader
  const svgRule = config.module.rule('svg')
  svgRule.uses.clear()
  svgRule.exclude.add(/node_modules/)
  svgRule.test(/\.svg$/).use('svg-sprite-loader').loader('svg-sprite-loader').options({
    symbolId: 'icon-[name]'
  }).end()

  // 修改images规则
  const imagesRule = config.module.rule('images')
  imagesRule.exclude.add(path.join(__dirname, 'src/icons'))
  config.module.rule('images').test(/\.(png|jpe?g|gif|svg)(\?.*)?$/).end()
}

配置完成,在页面上引入:

<svg-icon iconClass="history" className="icon"></svg-icon>

最后

截止到目前,准备工做算是完成,能够开始逻辑代码的编写啦。水平有限,能力通常,有什么不对的地方,欢迎你们不吝赐教。

## 代码仓库 ##

https://gitee.com/IanLew/tree-hole.git

## @树洞系列 ##

vue项目实践@树洞(一)

vue项目实践@树洞(二)

vue项目实践@树洞(三)

相关文章
相关标签/搜索