VueJS 开发常见问题集锦
由于公司的前端开始转向 VueJS,最近开始使用这个框架进行开发,遇到一些问题记录下来,以备后用。
主要写一些 官方手册 上没有写,但是实际开发中会遇到的问题,需要一定知识基础。
涉及技术栈
- CLI: Vue-CLI
- UI: Element
- HTML: Pug(Jade)
- CSS: Less
- JavaScript: ES6
polyfill 与 transform-runtime
首先,vue-cli 为我们自动添加了 babel-plugin-transform-runtime 这个插件,该插件多数情况下都运作正常,可以转换大部分 ES6 语法。
但是,存在如下两个问题:
1、异步加载组件时,会产生 polyfill 代码冗余
2、不支持对全局函数与实例方法的 polyfill
两个问题的原因均归因于 babel-plugin-transform-runtime 采用了沙箱机制来编译我们的代码(即:不修改宿主环境的内置对象)。
由于异步组件最终会被编译为一个单独的文件,所以即使多个组件中使用了同一个新特性(例如:Object.keys()),那么在每个编译后的文件中都会有一份该新特性的 polyfill 拷贝。如果项目较小可以考虑不使用异步加载,但是首屏的压力会比较大。
不支持全局函数(如:Promise、Set、Map),Set 跟 Map 这两种数据结构应该大家用的也不多,影响较小。但是 Promise 影响可能就比较大了。
不支持实例方法(如:'abc'.include('b')、['1', '2', '3'].find((n) => n < 2) 等等),这个限制几乎废掉了大部分字符串和一半左右数组的新特性。
一般情况下 babel-plugin-transform-runtime 能满足大部分的需求,当不满足需求时,推荐使用完整的 babel-polyfill。
替换 babel-polyfill
首先,从项目中移除 babel-plugin-transform-runtime
卸载该依赖:
npm un babel-plugin-transform-runtime -D
修改 babel 配置文件
// .babelrc
{
//...
"plugins": [
// - "transform-runtime"
]
//...
}
然后,安装 babel-polyfill 依赖:
npm i babel-polyfill -D
最后,在入口文件中导入
// src/main.js
import 'babel-polyfill'
ES6 import 引用问题
在 ES6 中,模块系统的导入与导出采用的是引用导出与导入(非简单数据类型),也就是说,如果在一个模块中定义了一个对象并导出,在其他模块中导入使用时,导入的其实是一个变量引用(指针),如果修改了对象中的属性,会影响到其他模块的使用。
通常情况下,系统体量不大时,我们可以使用 JSON.parse(JSON.stringify(str)) 简单粗暴地来生成一个全新的深度拷贝的 数据对象。不过当组件较多、数据对象复用程度较高时,很明显会产生性能问题,这时我们可以考虑使用 Immutable.js。
鉴于这个原因,进行复杂数据类型的导出时,需要注意多个组件导入同一个数据对象时修改数据后可能产生的问题。
此外,模块定义变量或函数时即便使用 let 而不是 const,在导入使用时都会变成只读,不能重新赋值,效果等同于用 const 声明。
在 Vue 中使用 Pug 与 Less
安装依赖
Vue 中使用 vue-loader 根据 lang 属性自动判断所需要的 loader,所以不用额外配置 Loader,但是需要手动安装相关依赖:
npm i pug -D
npm i less-loader -D
还是相当方便的,不用手动修改 webpack 的配置文件添加 loader 就可以使用了
使用 pug 还是 pug-loader?sass 两种语法的 loader 如何设置?
--- 请参考 预处理器 · vue-loader
使用
<!-- xxx.vue -->
<style lang="less">
.action {
color: #ddd;
ul {
overflow: hidden;
li {
float: left;
}
}
}
</style>
<template lang="pug">
.action(v-if='hasRight')
ul
li 编辑
li 删除
</template>
<script>
export default {
data () {
return {
hasRight: true
}
}
}
</script>
定义全局函数或变量
许多时候我们需要定义一些全局函数或变量,来处理一些频繁的操作(这里拿 AJAX 的异常处理举例说明)。但是在 Vue 中,每一个单文件组件都有一个独立的上下文(this)。通常在异常处理中,需要在视图上有所体现,这个时候我们就需要访问 this 对象,但是全局函数的上下文通常是 window,这时候就需要一些特殊处理了。
简单粗暴型
最简单的方法就是直接在 window 对象上定义一个全局方法,在组件内使用的时候用 bind、call 或 apply 来改变上下文。
定义一个全局异常处理方法:
// errHandler.js
window.errHandler = function () { // 不能使用箭头函数
if (err.code && err.code !== 200) {
this.$store.commit('err', true)
} else {
// ...
}
}
在入口文件中导入:
// src/main.js
import 'errHandler.js'
在组件中使用:
// xxx.vue
export default {
created () {
this.errHandler = window.errHandler.bind(this)
},
method: {
getXXX () {
this.$http.get('xxx/xx').then(({ body: result }) => {
if (result.code === 200) {
// ...
} else {
this.errHandler(result)
}
}).catch(this.errHandler)
}
}
}
优雅安全型
在大型多人协作的项目中,污染 window 对象还是不太妥当的。特别是一些比较有个人特色的全局方法(可能在你写的组件中几乎处处用到,但是对于其他人来说可能并不需要)。这时候推荐写一个模块,更优雅安全,也比较自然,唯一不足之处就是每个需要使用该函数或方法的组件都需要进行导入。
使用方法与前一种大同小异,就不多作介绍了。 ̄
自定义路径别名
可能有些人注意到了,在 vue-cli 生成的模板中在导入组件时使用了这样的语法:
```
import Index from '@/components/Index'
```
这个 @ 是什么东西?后来改配置文件的时候发现这个是 webpack 的配置选项之一:路径别名。
我们也可以在基础配置文件中添加自己的路径别名,比如下面这个就把 ~ 设置为路径 src/components 的别名:
// build/webpack.base.js
{
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'~': resolve('src/components')
}
}
}
然后我们导入组件的时候就可以这样写:
// import YourComponent from 'YourComponent'
// import YourComponent from './YourComponent'
// import YourComponent from '../YourComponent'
// import YourComponent from '/src/components/YourComponent'
import YourComponent from '~/YourComponent'
既解决了路径过长的麻烦,又解决了相对路径的烦恼,方便很多吧!
CSS 作用域与模块
组件内样式
通常,组件中 标签里的样式是全局的,在使用第三方 UI 库(如:Element)时,全局样式很可能影响 UI 库的样式。我们可以通过添加 scoped 属性来使 style 中的样式只作用于当前组件:
<style lang="less" scoped>
@import 'other.less';
.title {
font-size: 1.2rem;
}
</style>
在有 scoped 属性的 style 标签内导入其他样式,同样会受限于作用域,变为组件内样式。复用程度较高的样式不建议这样使用。
另,在组件内样式中应避免使用元素选择器,原因在于元素选择器与属性选择器组合时,性能会大大降低。
--- 两种组合选择器的测试:classes selector,elements selector
导入样式
相对于 style 使用 scoped 属性时的组件内样式,有时候我们也需要添加一些全局样式。当然我们可以用没有 scoped 属性的 style 来写全局样式。但是相比较,更推荐下面这种写法:
/* 单独的全局样式文件 */
/* style-global.less */
body {
font-size: 10px;
}
.title {
font-size: 1.4rem;
font-weight: bolder;
}
然后在入口文件中导入全局样式:
// src/main.js
import 'style-global.less'
获取表单控件值
通常我们可以直接使用 v-model 将表单控件与数据进行绑定,但是有时候我们也会需要在用户输入的时候获取当前值(比如:实时验证当前输入控件内容的有效性)。
这时我们可以使用 @input 或 @change 事件绑定我们自己的处理函数,并传入 $event 对象以获取当前控件的输入值:
<input type='text' @change='change($event)'>
change (e) {
let curVal = e.target.value
if (/^\d+$/.test(curVal)) {
this.num = +curVal
} else {
console.error('%s is not a number!', curVal)
}
}
当然,如果 UI 框架采用 Element 会更简单,它的事件回调会直接传入当前值。
v-for 的使用 tips
v-for 指令很强大,它不仅可以用来遍历数组、对象,甚至可以遍历一个数字或字符串。
基本语法就不讲了,这里讲个小 tips:
索引值
在使用 v-for 根据对象或数组生成 DOM 时,有时候需要知道当前的索引。我们可以这样:
<ul>
<li v-for='(item, key) in items' :key='key'> {{ key }} - {{ item }}
</ul>
但是,在遍历数字的时候需要注意,数字的 value 是从 1 开始,而 key 是从 0 开始:
<ul>
<li v-for='(v, k) in 3' :key='k'> {{ k }}-{{ v }}
<!-- output to be 0-1, 1-2, 2-3 -->
</ul>
2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。
模板的唯一根节点
与 JSX 相同,组件中的模板只能有一个根节点,即下面这种写法是 错误 的:
```
Title
```
我们需要用一个块级元素把他包裹起来:
```
Title
```
原因参考:React-小记:组件开发注意事项#唯一根节点
项目路径配置
由于 vue-cli 配置的项目提供了一个内置的静态服务器,在开发阶段基本不会有什么问题。但是,当我们把代码放到服务器上时,经常会遇到静态资源引用错误,导致界面一片空白的问题。
这是由于 vue-cli 默认配置的 webpack 是以站点根目录引用的文件,然而有时候我们可能需要把项目部署到子目录中。
我们可以通过 config/index.js 来修改文件引用的相对路径:
build.assetsSubDirectory: 'static'
build.assetsPublicPath: '/'
dev.assetsSubDirectory: 'static'
dev.assetsPublicPath: '/'
我们可以看到导出对象中 build 与 dev 均有 assetsSubDirectory、assetsPublicPath 这两个属性。
其中 assetsSubDirectory 指静态资源文件夹,也就是打包后的 js、css、图片等文件所放置的文件夹,这个默认一般不会有问题。
assetsPublicPath 指静态资源的引用路径,默认配置为 /,即网站根目录,与 assetsSubDirectory 组合起来就是完整的静态资源引用路径 /static。
写到这里解决方法已经很明显了,只要把根目录改为相对目录就好了:
build.assetsSubDirectory: 'static'
build.assetsPublicPath: './'
没错!就是一个 . 的问题。
文章还在完善中,欢迎大家一起讨论 Vue.JS 开发中遇到的一些问题哈 /
话说收藏好多,你确定收藏了会记得看吗_
读一读开发的时候至少会有个印象,点个赞打卡啦~
原文:VueJS 开发常见问题集锦
https://blog.beard.ink/JavaScript/VueJS-开发常见问题集锦/
更多前端文章http://www.jqhtml.com
VueJS 开发常见问题集锦的更多相关文章
- Vue 开发常见问题集锦
涉及技术栈 CLI: Vue-CLI UI: Element HTML: Pug(Jade) CSS: Less JavaScript: ES6 正文: polyfill 与 transform-ru ...
- eclipse 开发常见问题集锦
问题1: eclipse导入外部项目,中文显示乱码(如下图) 方案:项目名-->右键属性-->如下图: 问题2: jsp/html页面eclipse双击打开,代码在工作区不显示(如下图:) ...
- 【小梅哥SOPC学习笔记】SOPC开发常见问题及解决办法集锦
SOPC开发常见问题及解决办法集锦 一.Symbol 'NULL' could not be resolved 近期在评估使用NIOS II处理器进行项目的开发,我使用的软件是Quartus II 1 ...
- XBOX ONE游戏开发常见问题
XBOX ONE游戏开发常见问题 终于弄懂这个在Unity的sdk在Account Picker切换账号的机制了,一个手柄注册一个账号,在游戏里面的时候,只有另外一个手柄选择自己的账号,系统的Acti ...
- Xamarin 开发常见问题
原文:Xamarin 开发常见问题 Verify the project is selected to be deployed in the Solution Configuration Manage ...
- iOS 开发问题集锦(三)
iOS 开发问题集锦(三) 介于群里大部分童鞋都是新手,为了大家能够更好的提问,并且提的问题能更好的得到回答,下面写几点提问时的注意事项: 1.认真对待你的问题,在提问题前有过认真的思考: 2.先在 ...
- VueJs(2)---VueJs开发环境的搭建和讲解index.html如何被渲染
VueJs开发环境的搭建和讲解初始框架 有关如何搭建vue.js框架我这看了一篇文章,自己也根据它进行搭建环境. 文章地址:vue.js2.0实战(1):搭建开发环境及构建项目 接下来对初始的框架进行 ...
- 【前端技术】web 开发常见问题--GET POST 区别
web 开发常见问题--GET POST 区别 首先,get和post是什么? --两种 HTTP 请求方法:GET 和 POST HTTP Request Methods GET.POST 专业 ...
- ARKit从入门到精通(11)-ARKit开发常见问题及解决方案
转载请注明出处:ARKit从入门到精通(11)-ARKit开发常见问题及解决方案 本文主要介绍ARKit开发过程中一些常见问题 1.ARKit框架无法导入问题 2.ARKit运行黑屏或者白屏问题:Un ...
随机推荐
- jq 禁用复选框 和输入框
$('input').attr("readonly", ""); $('input').attr("disabled", "fal ...
- react 基础篇 #2 create-react-app
1. 介绍 在开发react应用时,应该没有人用传统的方法引入react的源文件(js),然后在html编辑吧. 大家都是用webpack + es6来结合react开发前端应用. 这个时候,我们可以 ...
- hadoop spark 总结
yarn 由,资源管理器rm,应用管理器am appMaster,节点管理器nm 组成! 图侵删 yarn 的设计,是为了代替hadoop 1.x的jobtracker 集中式一对多的资源管理「资源 ...
- 记Python学习
上周学的Python,感觉有点忘了,现在回顾一下... 一.Python安装及测试:https://www.cnblogs.com/weven/p/7252917.html 例子: Python自带的 ...
- PAT_A1146#Topological Order
Source: PAT A1146 Topological Order (25 分) Description: This is a problem given in the Graduate Entr ...
- PAT_A1109#Group Photo
Source: PAT A1109 Group Photo (25 分) Description: Formation is very important when taking a group ph ...
- android apk的签名和权限问题
一. android apk的签名问题(http://blog.csdn.net/lyq8479/article/details/6401093) 1.为什么要给Android应用程序签名? ...
- jQuery cxCalendar 日期选择器
简介 cxCalendar 是基于 jQuery 的日期选择器插件. 它灵活自由,你可以自定义外观,日期的范围,返回的格式等. 版本: jQuery v1.7+ jQuery cxCalendar v ...
- django-celery-win10
setting初始化: 定时任务 增加tasks 启动:
- Oracle笔记 多表查询
Oracle笔记 多表查询 本次预计讲解的知识点 1. 多表查询的操作.限制.笛卡尔积的问题: 2. 统计函数及分组统计的操作: 3. 子查询的操作,并且结合限定查询.数据排序.多表查询.统计查 ...