VueJS 开发常见问题集锦

框架

浏览数:416

2017-8-3

由于公司的前端开始转向 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 }}
</li></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 -->
</li></ul>

2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。

模板的唯一根节点

  与 JSX 相同,组件中的模板只能有一个根节点,即下面这种写法是 错误 的:

<template>
  <h1>Title</h1>
  <article>Balabala...</article>
</template>

  我们需要用一个块级元素把他包裹起来:

<template>
  <div>
    <h1>Title</h1>
    <article>Balabala...</article>
  </div>
</template>

原因参考: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-开发常见问题集锦/

VueJS 开发常见问题集锦相关推荐

  1. eclipse 开发常见问题集锦

    问题1: eclipse导入外部项目,中文显示乱码(如下图) 方案:项目名-->右键属性-->如下图: 问题2: jsp/html页面eclipse双击打开,代码在工作区不显示(如下图:) ...

  2. php开发经典问题,PHP开发常见问题集锦(一)

    1,如果一个图片在ie不可以显示,在其他浏览器显示 可能原因:该图片是CMYK颜色 解决方法:在ps中将其改成RGB颜色 2,window.location.href='http://user.ci1 ...

  3. ArcGIS Server常见问题集锦(转载)

    ArcGIS Server常见问题集锦(转载) 安装部署问题 1 用户名问题    在GIS Server PostInstall过程中会涉及到两个用户,默认情况下一个ArcGISSOM,一个是Arc ...

  4. mysql general bin区别_MySQL_Mysql常见问题集锦,1,utf8_bin跟utf8_general_ci的区别 - phpStudy...

    Mysql常见问题集锦 1,utf8_bin跟utf8_general_ci的区别 ci是 case insensitive, 即 "大小写不敏感", a 和 A 会在字符判断中会 ...

  5. pythonocc常见问题集锦

    总目录 >> PythonOCC入门进阶到实战(目前已更新入门篇.基础篇和进阶篇) 如果你有什么不懂,欢迎加入pythonocc中文社区:860536842 工作招募,一起来实现国产云端C ...

  6. Android常见问题集锦

    Android常见问题集锦 前言:在开发中,每个人或多或少会遇到各种各样的问题,有些问题依据代码思路调试就可以定位出来,而大部分的问题都是经验性问题,遇到过就很容易解决,但在第一次遇到时往往会花费大量 ...

  7. Unity 4.x游戏开发技巧集锦(内部资料)

    2019独角兽企业重金招聘Python工程师标准>>> Unity 4.x游戏开发技巧集锦(内部资料) 淘宝书店地址:http://item.taobao.com/item.htm? ...

  8. [Android问答] 开发环境问题集锦

    [Android问答] 开发环境问题集锦 工欲善其事,必先利其器. 和iOS开发相比,Android的开发环境的版本比较多,随之而来的问题也多.显然,我们不应该浪费宝贵的时间在解决开发环境带来的问题上 ...

  9. Android开发问题集锦

    本文来自:安卓航班网 简介:这是[Android底层开发]Android开发问题集锦,介绍了和java,有关的知识.技巧.经验,和一些java源码等. 1.Android Market上发软件要注意哪 ...

最新文章

  1. 【Harvest源码分析】GetWaveformAndSpectrumSub函数
  2. 原始尺寸_螺母尺寸检测,螺丝螺母外观检测设备
  3. 几分钟了解阿里云云服务器ECS
  4. VS2012无法安装cocos2d-x-2.1.4 解决方法及VS2012新建coco2d-x项目(一)
  5. burp的intruder报错Payload set 1: Invalid number settings
  6. 【Unity与23种设计模式】访问者模式(Visitor)
  7. 在 Laravel 应用中使用 pjax 进行页面加速
  8. java regex 正则表达式 提取数字和去除数字,过滤数字,提取价格
  9. 令仔代码收藏系列(二)----BASE64编码
  10. 打包Hololens2 VS error MSB3774: 找不到 SDK“WindowsMobile, Version=10.0.19041.0”解决办法
  11. flash加载脚本文件导致IE脚本错误 ,行53 ,字符3,缺少对象,代码0 , 怎么解决?
  12. 青岛小学 初中有计算机编程比赛,2017年青岛中小学信息技术竞赛活动.doc
  13. 【例题4-2 uva489】Hangman Judge
  14. Q4营收突破20亿且连续四个季度盈利斗鱼驶入“后直播时代”快车道
  15. JXL开发Excel文档中文教程
  16. ArchiCAD与Revit深度对比
  17. 云计算 码率适配限速_一种基于云计算的应用于用户终端的测速方法
  18. matlab int 32,Matlab数字
  19. 安卓串口通信 CH340 341
  20. 关于全球央行数字货币实验的若干认识与思考

热门文章

  1. 如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集
  2. 第一章 计算机、程序和Java概述 复习题 解答
  3. sqlite-常用语句
  4. Qt 事件处理机制-qt源码解读
  5. Windows系统云服务器安装、配置 MySQL 数据库
  6. MFC/VC++中怎样设置位图按钮并且位图不会覆盖文字——–位图按钮
  7. IOS基础之愤怒的小方块
  8. Java之文件流操作的文件读写
  9. Linux大文件格式,linux – 用于打印大文件的命令,按大小以人类可读的格式排序...
  10. 硬盘安装以及磁盘分区和检测(笔记本R7000)