vue项目实践@树洞(二)
书接上文
上一篇粗略地搭建了项目,运行一下,编译通过,但是控制台上打出一个红色错误警告!报错了?!什么情况,还没做事就错了,来看看什么错!
'Locale' is defined but never used,就是说Locale这个变量没有使用。在引入UI组件库的时候,我的编辑器已经错误提示了,莫名其妙嘛。并非这个错抛得莫名其妙,而是这个错不是自己造成的。设想一下,在插件的基础上加了很复杂的逻辑,这时来一个这样莫名其妙的错,是不是很无语。这只是一个假想,绝大多数情况不会是插件带来的。不过,我还是选择自己撸代码,不去使用所谓的插件,除非使用例如Babel之类的工具。
除此之外,使用ESLint还会有更多的错误提示。比如,配置postcss.config.js的时候也会给出错误警告,我在上一篇文章给的配置文件的key使用的是双引号,它会提示使用单引号。再比如,ES推荐使用箭头函数,在某些时候没用使用箭头函数也会跑错,特别是使用插件。代码提示会抛出很多语法上的错误提示,如果开了ESLint,那就按着它的提示来培养代码编写习惯吧。
// 重新给一下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没有设置大小,所以一直保持这个尺寸。
试着改变浏览器大小,这时这些元素也会随之变化,这样就无需JS去监听resize事件。这时它的好处,也算得上是缺点:它是根据视窗发生变化的,所以移动端和PC端必须分开。使用rem可以设置一个峰值,当监听到视窗宽度达到峰值就按一倍像素展示不再缩放,vw则不能。
小到iPhone 5,大到iPad,效果都还不错,可以下一步了。
网络请求
## 拦截封装 ##
网络请求是一个必然,我准备使用axios,这个库使用的ES6语法,就很棒。
# 安装axios npm i -D axios
在src下新建一个apis的目录,做一个简单的拦截封装。这个封装我在别的项目用过,数据请求都没问题,由于这个项目缺少后端接口的环节,因此暂且只是一个普通的封装。
// 封装拦截 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项目实践@树洞(二)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
在Ignite中自定义身份认证安全插件
Ignite集群搭建完成之后,应用就可以接入集群进行各种操作了,但是默认的集群,没有安全保护机制,任何应用、支持JDBC的客户端,只要知道集群节点的IP地址,都可以接入集群,这造成了一定的安全风险,这对于持有敏感数据的用户,显然是无法接受的。 Ignite本身有一个简单的安全模块,提供了一个基于用户名/密码的认证机制,但是在实际业务场景中,需求往往更复杂,本文以白名单认证方式为例,讲述如何通过自定义安全插件的方式,满足自己的业务需求。 插件 Ignite有一个设计良好的模块化架构和插件机制,可以配置不同的模块,也可以自定义自己的插件。本文会介绍如何替换掉默认的安全实现。 第一步是在IgniteConfiguration中注入一个插件,本示例采用基于XML的配置,配置如下: <bean id="ignite" class="org.apache.ignite.configuration.IgniteConfiguration" p:gridName="mygrid"> <property name="pluginConfigurations"> <bean ...
- 下一篇
彻底解决Spring mvc中时间的转换和序列化等问题
痛点 在使用Spring mvc 进行开发时我们经常遇到前端传来的某种格式的时间字符串无法用java8的新特性java.time包下的具体类型参数来直接接收。 我们使用含有java.time封装类型的参数接收也会报反序列化问题,在返回前端带时间类型的同样会出现一些格式化的问题。今天我们来彻底解决他们。 建议 其实最科学的建议统一使用时间戳来代表时间。这个是最完美的,避免了前端浏览器的兼容性问题,同时也避免了其它一些中间件的序列化/反序列化问题。但是用时间表达可能更清晰语义化。两种方式各有千秋,如果我们坚持使用java8的时间类库也不是没有办法。下面我们会以java.time.LocalDateTime为例逐一解决这些问题。 局部注解方式 网上有很多文章说该注解是前端指向后端的,也就是前端向后端传递时间参数格式化使用的,这没有错!但是有一个小问题,该方式只能适用于不涉及反序列化的情况下。也就是以下场景才适用: @GetMapping("/local") public Map<String, String> data(@DateTimeFormat(pattern = "yyy...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Linux系统CentOS6、CentOS7手动修改IP地址
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能