Vue开发常见问题

摘要

现在的前端发展可以说是日新月异,新技术、新东西层出不穷。新技术、新东西的出现带来的变化便是开发模式的转变。传统的开发模式已经慢慢地被前后端分离模式所取代。正是这种开发模式的转变,使得前端开发人员要学习的东西越来越多,技术水平要求也越来越高。

现在的前端发展可以说是日新月异,新技术、新东西层出不穷。新技术、新东西的出现带来的变化便是开发模式的转变。传统的开发模式已经慢慢地被前后端分离模式所取代。正是这种开发模式的转变,使得前端开发人员要学习的东西越来越多,技术水平要求也越来越高。

纵观前端的发展历程:jQuery处理了浏览器的兼容性问题,方便了DOM操作;Vue、Angular、React以MV*模式取代了传统的DOM操作,以数据驱动视图,极大的提高了页面性能。以目前的发展趋势来看,MV*模式将会成为未来前端发展的主流方向。

使用vue-cli开发的同学,笔者建议使用最新稳定版的VS Code,原因如下:

1、一款好的编辑器能极大提高工作效率,这就是我们常说的:工欲善其事,必先利其器。

2、VS Code是近几年“异军突起”的一款免费开源软件,小巧、轻便、启动迅速、资源占用低,合理的插件扩展让你书写代码有一种畅快淋漓感。

如何让WebStrom忽略node_modules的索引

用WebStrom开发的同学,应该会发现WebStrom在打开一个项目的时候会有一个索引过程。如果电脑配置不高的同学,打开一个带有node_modules文件夹的项目,那简直就是一场“灾难”。为了提高打开速度,避免每次“灾难”的重现,我们可以这样做:

File -> Setting -> Editor -> File types -> Ignore files and folders

在Ignore files and folders最后加上node_modules;保存就可以了,然后重启WebStorm一切就将改变。

特别说明,以下是针对vue2.0总结的问题,部分通用于vue1.0。

提醒:npm install等价于npm i,--save等价于-S,--save-dev等价于-D。一个是完整命令,一个是快捷命令。npm cache clean的别名为npm cache clear和npm cache rm。

使用vue-cli构建vue项目

理由:vue-cli用于快速构建vue的应用。它的优点是进一步屏蔽了很多配置的步骤、自动按官方推荐的模式进行代码组织、自动生成组件/服务等模板以及更方便的发布和测试代码。

特别说明:$符号是某些类DOS系统特有的,后面才是真正的执行命令(敲入$之后的命令即可),很多新手都会在这里犯错。

1、安装Node最新版本(推荐使用LTS版,该版本为长期稳定版)

2、替换npm为淘宝镜像(如无必要,尽量不要使用镜像)

---->卸载cnpm命令(npm uninstall cnpm -g),此条只针对全局安装过cnpm的人

注:打开DOS面板,执行npm config set registry https://registry.npm.taobao.org

如果想恢复默认,打开DOS面板,执行npm config set registry https://registry.npmjs.org

特别说明:替换npm为淘宝镜像原因是因为npm在国内访问不太稳定。当然,如果你的网络访问npm没问题,可忽略这步;

特别强调:淘宝镜像和cnpm是不一样的,这里设置的是淘宝镜像而不是cnpm。经过笔者多次踩坑和血淋淋的教训得出的结论——珍爱生命,远离cnpm

3、安装vue-cli(建议先清一下缓存:npm cache clean)

npm install vue-cli -g

4、初始化项目

vue init webpack vue-demo

注:此处的webpack和vue-demo可以替换为别的,根据项目使用的模版选择对应的即可。如果是学习vue使用,建议使用webapck模板。

特别说明:安装过程中会有提示,根据提示走即可,回车或输入对应命令即可进行下一步

友情提示:Vue build有两种方式(这两种打包方式对用户没区别)

第一种是Runtime + Compiler方式——打包的是/node_modules/vue/dist/vue.js

第二种是Runtime-only方式——打包的是/node_modules/vue/dist/vue.common.js

当我们使用.vue文件开发时,推荐使用Runtime-only,这样可以让体积减轻6k左右。

5、项目初始化完成后,根据提示进行即可

vue文件中使用Scss/Stylus/Less

特别说明:以下操作是针对使用webpack模版初始化项目的。

1、如果想在vue组件中使用Scss,需要在package.json里的devDependencies加node-sasssass-loader

特别提醒:vue组件里的style里需加上lang="scss",这样才能被webpack识别

1、如果想在vue组件中使用Stylus,需要在package.json里的devDependencies加stylusstylus-loader

特别提醒:vue组件里的style里需加上lang="stylus",这样才能被webpack识别。

高能预警:这里用的是stylus-loader而不是style-loader;stylus对缩进要求极其严苛,这点真的和Python很像,你不注意,webpack就敢给你报错,所以请注意缩进。

1、如果想在vue组件中使用Less,需要在package.json里的devDependencies加lessless-loader

特别提醒:vue组件里的style里需加上lang="less",这样才能被webpack识别

2、.eslintrc.js文件加入

  1. // 允许自由缩进
  2. 'indent': 0,
  3. // JS语句必须以分号结束
    'semi': ['error', 'always'],
  4. // 允许使用宽松运算符
  5. 'eqeqeq': 0,
  6. // 允许三目运算中使用布尔值
  7. 'no-unneeded-ternary': 0,
  8. // 允许使用表达式
  9. 'no-unused-expressions': 0,
  10. // 函数定义时,function关键字后面不加空格
  11. 'space-before-function-paren': 0

特别说明:如果你没有选择eslint规范JS代码,可忽略这步(此代码是笔者常用配置项)。具体如何配置,参考eslint官网

3、重新npm install

4、安装完成,执行npm run dev就可以了

5、按提示进行修改即可

特别说明:此处修改是因为刚才咱们配置过eslint导致的报错,按提示修改代码即可

如何在全局引入Scss的变量声明

笔者习惯于使用Scss,因此给出Scss的解决方法,其它CSS预处理器自行搜索。

相信很多朋友已经习惯于在用到Scss变量的组件中每次导入Scss变量文件的做法。这种做法代价较高且依赖性强(体现在路径不能随意修改,否则牵一发而动全身)。

因此,全局引入Scss变量的做法来更替次次组件导入的方法显得尤为合适。你可以和笔者一样写一个公用的mixin.scss文件(里面不仅能放变量声明,还可以放mixin等),然后一次引入,.vue文件中开箱即用(不需导入)。

方法如下:

1、安装sass-resources-loader

npm install sass-resources-loader --save-dev

2、打开build/utils.js文件,修改对应代码如下:

  1. scss: generateLoaders('sass').concat(
  2.   {
  3.     loader: 'sass-resources-loader',
  4.     options: {
  5.       resources: path.resolve(__dirname, '../src/common/scss/mixin.scss')
  6.     }
  7.   }
  8. ),

注意:上面的文件路径一定要根据自己的项目来写,不要一味照抄

npm安装依赖报错

当我们使用npm安装依赖时,很多时候会出现一堆报错。报错的原因是多数是因为在node scripts/install阶段会从github上下载一个.node文件。而GitHub Releases里的文件都托管在s3.amazonaws.com上面,而这个托管网址在国内访问极度不稳定的,所以当依赖包含有node-sass、electron、phantomjs等依赖时会报错。

解决方法:

在C:\Users\Administrator目录下找一个为.npmrc的文件(没有可以自己新建一个),打开该文件并添加对应包的淘宝镜像即可(第四行代码是将npm默认地址替换为淘宝镜像,如果已经设置过淘宝镜像只须添加对应报错依赖项即可,笔者给出常见报错依赖项的淘宝镜像,推荐这三项都添加进去)。然后删除项目的node_modules文件夹,重新安装依赖(建议安装依赖前执行一下清除npm缓存操作:npm cache clean)。

  1. sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
  2. electron_mirror=https://npm.taobao.org/mirrors/electron/
  3. phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
  4. registry=https://registry.npm.taobao.org

启动项目,端口被占用

排除一些软件默认使用指定端口的情况外,最大的可能性是之前有用Node运行过其它项目导致端口被占用。如果是后面这种情况,最简单的方法就是通过任务管理器结束掉所有Node进程,然后再执行项目启动命令即可。

当然,如果你喜欢折腾,你也可以去修改webpack的配置文件来更改默认的端口,然后再执行项目启动命令即可。相比这种方式,笔者更推荐通过任务管理器结束掉所有Node进程的方式。

vue文件中的样式不生效

按照Vue官方给出的说法,style身上加上scoped可以让样式“私有化”(即只针对本vue文件中的代码有效,不会对别的代码造成样式覆盖问题)。很多时候,我们引入了第三方UI,在vue文件中进行样式覆盖不生效,多半问题是style上的scoped导致的。

解决方案:将需要覆盖样式的这部分代码放到单独的CSS文件中,最后在main.js文件中导入即可。

防止Vue在解析时出现闪烁

针对这个问题,解决方法如下:

官网为我们提供了一个v-cloak指令,我们只需要这样写即可:

  1. // CSS代码
  2. [v-cloak] {
  3.   display: none;
  4. }
  5. // HTML代码
  6. <div v-cloak>{{ message }}</div>

除了上述方法外,我们还可以借助Vue的v-text和v-html指令,同样可以达到效果。这两个指令的区别在于,v-html会解析HTML代码,而v-text不会。这几种方法,可根据自己的需要选择使用。

vue组件异步加载

将一个组件(以及其所有依赖)改为异步加载,只需要把:

import HelloWorld from '@/components/HelloWorld'

改成

const HelloWorld = () => import('@/components/HelloWorld')

vue项目引入jQuery和Bootstrap

引入其它第三方JS步骤类似

1、npm安装expose-loader(webpack官方推荐方式)

npm install expose-loader -S

2、npm安装jQuery和Bootstrap

npm install jquery bootstrap -S

3、修改build文件夹下的webpack.base.conf.js

  1. module: {
  2.     rules: [{
  3.         test: require.resolve('jquery'),
  4.         use: [{
  5.             loader: 'expose-loader',
  6.             options: 'jQuery'
  7.         },
  8.         {
  9.             loader: 'expose-loader',
  10.             options: '$'
  11.         }]
  12.     }]
  13. }

4、修改main.js

  1. import 'bootstrap/dist/css/bootstrap.min.css';
  2. /* eslint-disable no-unused-vars */
  3. import $ from 'jquery';
  4. import 'bootstrap';

5、如果要在某个组件中使用$,请在对应的组件中导入jQuery即可

import $ from 'jquery';

注:请使用npm执行上面的步骤,切勿使用cnpm、切勿使用cnpm、切勿使用cnpm。如果npm安装无法安装,可以使用淘宝镜像——淘宝镜像和cnpm是不一样的,设置淘宝镜像可以参考文章开头部分。

router-link里的元素点击加stop失效

出现这个问题,多半是因为你使用了默认的router-link标签,默认vue会将这个解析为a标签。

解决办法如下,因为router-link可以指定tag,所以我们可以利用这个属性将默认的a链接换成其它标签再给加点击事件的元素加上stop就可以完美解决。

vue-resource拦截和axios拦截

有些时候,我们在处理页面请求的时候需要对页面进行类似token过期的处理。如果我们每个页面都去设置将是一个非常庞大的工程。因此,借助全局拦截器来进行统一设置将是最方便快捷的处理方法。下面介绍一下如何配置全局的vue-resource拦截器axios拦截器

注:此代码放在main.js文件中,并且在main.js中导入vue-resource或axios再进行如下配置

  1. // 导入并挂载
  2. import VueResource from 'vue-resource';
  3. Vue.use(VueResource);
  4. // vue-resource拦截配置
  5. Vue.http.interceptors.push((req, next) => {
  6.     // 请求头设置,此设置根据后台要求进行配置
  7.     Vue.http.headers.common['要传的字段'] = '要传的内容';
  8.     // 此处可以配置请求拦截设置
  9.     if (req.method.toLowerCase() == 'post') {
  10.         req.emulateJSON = true;
  11.     }
  12.     // 此处可以配置请求拦截设置
  13.     next((res) => {
  14.         // 此处可以配置响应拦截设置
  15.         return res;
  16.     });
  17. });
  18. // 导入
  19. import axios from 'axios';
  20. // 针对只支持application/x-www-form-urlencoded的全局设置(qs模块为Node内置模块,无需单独安装)
  21. import qs from 'qs';
  22. // axios请求拦截器
  23. axios.interceptors.request.use((req) => {
  24.     // 请求头设置,此设置根据后台要求进行配置
  25.     req.headers['要传的字段'] = '要传的内容';
  26.     // 此处可以配置请求拦截设置
  27.     if (req.method.toLowerCase() == 'post') {
  28.         req.data = qs.stringify(req.data);
  29.     }
  30.     return req;
  31. });
  32. // axios响应拦截器
  33. axios.interceptors.response.use((res) => {
  34.     // 此处可以配置响应拦截设置
  35.     return res;
  36. });
  37. // 由于受vue-resource的影响,大多数人沿袭了之前的风格,进行全局配置axios
  38. Vue.prototype.$http = axios;

vue-resource传参和axios传参报错

在用AJAX做数据交互的过程中,避免不了的就是参数传递,因为是在使用Vue进行开发,那么我们就会用搭配的AJAX工具,无论我们是用vue-resource或axios,在POST传参方面都不会像jQuery那样顺利。使用这两个工具,不传参什么事都没有,一传参它们就立马报错。原因在于vue-resource和axios默认传参是以JSON形式进行传递,大多数服务器默认并不支持接收JSON数据,所以可以通过下面的配置将JSON形式改成通用形式。

针对vue-resource的解决方案是,在POST传参的时候加一个配置项:{emulateJSON: true}

  1. this.$http.post('/someUrl', {foo: 'bar'}, {emulateJSON: true})
  2. .then((res) => {
  3.     console.log(res);
  4. }, (err) => {
  5.     console.log(err);
  6. });

针对axios的解决方案是,在POST传参的时候利用qs模块进行格式化:qs.stringify()

在使用axios的页面导入Node的qs模块

  1. import qs from 'qs';
  2. this.$http.post('/user',
  3. qs.stringify({
  4.     firstName: 'Fred',
  5.     lastName: 'Flintstone'
  6. }))
  7. .then((res) => {
  8.     console.log(res);
  9. })
  10. .catch((err) => {
  11.     console.log(err);
  12. });

特别说明:如果你想像vue-resource那样使用this.$http,只需要在main.js中将axios挂载到Vue的原型上面即可Vue.prototype.$http = axios;如果你不想那么麻烦,你可以使用拦截器进行全局配置,具体配置可以参考上一个问题。

这里笔者发表一下自己的看法,使用axios有一段时间了,没发现axios比vue-resource好多少,问题到是发现了几个。

1、axios不支持JSONP,官方好像怕出安全问题。

2、对于官方readme中提供的application/x-www-form-urlencoded的设置方法,至少目前一点作用没有,还要借助qs模块来完成。对于这个bug,不少人都有在Issues反馈,官方却一直没有解决。

如果vue作者没有推荐axios,笔者相信基本不会有人使用axios,毕竟vue-resource经历了vue2.0之前版本的检验,而且依然支持现在的版本。

AJAX进行header传值报错

在 进行项目开发的过程中,有些时候我们需要通过header进行传值。对于像PHP、Java、Objective-C等是在正常不过的一种传值方式。但是,对于像使用jQuery、axios等用AJAX来进行header传值的人来说,就不是那么容易了。如果仅仅只是前端配置header,后端没提前做过设置,控制台会报错(大意是说:请求头在服务器响应中不存在)。

要解决这个问题,只需要后端进行一下设置即可。header传值报错根本问题在于服务端的设置,即是否允许前端提交自定义header

下面笔者给出方法:

  1. // 比如要用header传递X-AA-TOKEN,那就在下面这句话里加上X-AA-TOKEN即可
  2. header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X-AA-TOKEN');

本地模拟数据,AJAX请求路径报错

本地模拟数据(笔者以data.json为例)是在开发过程中常见的一种模拟前后端交互的方式。当然了,如果条件允许最好以真实接口为准,毕竟模拟数据的网络请求及数据处理过程远没有真实环境复杂。因此,很容易让我们忽略掉一些生产环境中交互的细枝末节。

在 用vue-cli搭建的项目中,要避免路径出错,最好先了解一下生成项目后的文件目录结构(打包后的文件除了index.html外,其余文件都会放到 static文件夹里)。换句话说,原static文件夹里的东西,在打包后会不做变动。利用这一特点,我们可以将本地模拟数据放到static文件夹里,然后用到AJAX的地方路径改为'./static/data.json'或'static/data.json'即可解决路径报错问题,此方法仅支持get方式

打包之后静态资源图片404问题

很多同学都遇到过这种问题,当我们通过npm run build打包之后将文件放在服务器上时会出现图片404问题。这些图片可能是以img方式引入, 也可能是在CSS中定义的背景图片。

针对这个问题,首页要说明一下:在以vue-cli初始化的webpack模板中,webpack默认设置会将不大于10K的图片转成base64,大于10K的会保留原方式,并且最终会以hash命名的方式打包进static文件夹里(仅针对大于10K的图片)。

知道了这一点,多种解决方法也就出来:

1、可以通过修改webpack设置,将默认10K大小根据需要改大一点;

2、可以将图片和组件放在一个文件夹里,然后引入(笔者常用的方式),要使用相对路径(./或../)开头;

3、可以将图片做成外链图片,引入绝对地址;

4、可以将图片放到static文件夹里,然后引入。用这种方式的同学,在写路径时一定要找对,要不然会报错的。

以上方法任选其一即可,笔者推荐第2种或第3种方法。

路由执行了,但是却没有显示对应的组件

有些时候我们在进行路由切换的时候会发现路由已经执行(url已经发生了改变),但是却没有显示对应的组件。

经笔者测试,出现这种问题的原因多数是因为组件的data书写有问题。在vue的组件中,data必须为函数且参数需以return的行式返回出来。

选择性使用keep-alive

有些时候,我们的项目中需要对某些页面进行缓存处理来达到某些需求。这时,我们便会用到vue中的keep-alive。笔者见到大多数人在使用keep-alive时都是对所有组件进行缓存,对于这种做法,笔者认为弊大于利。原因在于:现在我们接触的项目页面一般都不会太少,如果我们把每个页面都缓存到内存中,一旦页面过多,必然影响手机的反映速度和流畅性。

因此,笔者的建议就是选择性组件缓存。要实习这种选择性组件缓存其实并不难,我们只需要在配置路由和使用view-router时做些手脚即可达到效果。

配置路由时,我们可以在我们需要进行缓存的组将多加一个参数(有meta字段的组件代表要缓存,没有则不需要),代码如下:

  1. routes: [
  2.     {
  3.         path: '/home',
  4.         name: 'home',
  5.         component: home,
  6.         meta: {
  7.             keep: true
  8.         }
  9.     },
  10.     {
  11.         path: '/mall',
  12.         name: 'mall',
  13.         component: mall
  14.     }
  15. ]

将原来使用view-router的代码替换成如下代码:

  1. <keep-alive>
  2.     <router-view v-if="$route.meta.keep"></router-view>
  3. </keep-alive>
  4. <router-view v-if="!$route.meta.keep"></router-view>

如何将vue组件通过use的方式全局调用

很多时候,我们希望自己也能做出一个vue组件,通过在main.js里use一下就可以到处用,而不用每次import。其实官方有给我们提供方法的,按着官方方法来就行了。

vue官方推荐的组件写法是通过文件来的方式,笔者以loading组件为例(loading组件文件夹包含loading.vue和index.js两个文件)

在loading文件夹里新建一个index.js,然后写上如下代码即可:

  1. // loading即为我们的loading组件
  2. import loading from './loading';
  3. // install是官方提供的一个方法,loading这就是后面可以全局使用的组件名字,此名字可以修改
  4. export default {
  5.   install(Vue) {
  6.     Vue.component('loading', loading);
  7.   }
  8. };

然后在main.js入口文件里增加如下代码:

  1. // 导入loading组件,引入路径根据自己的书写
  2. import loading from 'loading组件路径';
  3. // 利用Vue.use挂载我们的loading组件
  4. Vue.use(loading);

通过上面的步骤,我们就可以在全局使用loading标签成功引入loading组件了。

dist文件部署显示空白问题

打包生成后的文件放到服务环境下,访问空白,请注意下面两点:

1、确保dist文件夹里的东西放到了网站根目录下(即常见的www文件夹里)

特别说明:不是将dist文件夹放到网站根目录下,而是把dist文件夹里的东西放到网站根目录下。

2、是否使用的是IE系列浏览器打开的网址

特别说明:原因在于IE系列浏览器不支持JS的一些高级特性,因此我们需要借助babel-polyfill来实现高级特性转换。

-->安装babel-polyfill

npm install babel-polyfill -S

-->在main.js的第一行引入babel-polyfill

import 'babel-polyfill';

特别说明

1、babel-polyfill属于生产依赖,所以必须使用-S安装;

2、由于要用其做语法转换,所以要确保import 'babel-polyfill'是在main.js的第一行;

dist文件部署后刷新出现404问题

文件部署到服务器后,直接访问没有问题,但是刷新当前页后出现404问题。出现这个问题,99.99%是因为你在配置路由的时候启用了history模式。 起用history模式后,在开发环境不会出现刷新后404问题。但是,部署到服务器环境是需要对服务器做相关配置的。

解决方案:找到对应的服务器,把对应的代码放到对应的位置即可

  1. # Apache代码,加入到网站的.htaccess里,没有该文件,自己可以新建一个
  2. <IfModule mod_rewrite.c>
  3.   RewriteEngine On
  4.   RewriteBase /
  5.   RewriteRule ^index\.html$ - [L]
  6.   RewriteCond %{REQUEST_FILENAME} !-f
  7.   RewriteCond %{REQUEST_FILENAME} !-d
  8.   RewriteRule . /index.html [L]
  9. </IfModule>
  10. # Tomcat代码,加入到网站的web.xml里,没有该文件,自己可以新建一个
  11. <web-app>
  12.   <error-page>
  13.     <error-code>404</error-code>
  14.     <location>/index.html</location>
  15.   </error-page>
  16. </web-app>
  17. # Nginx代码,加入到网站的nginx.conf里,没有该文件,自己可以新建一个
  18. location / {
  19.   try_files $uri $uri/ /index.html;
  20. }

如何将打包好的文件放到指定目录

很多时候,我们因为某些原因不能将打包好的dist文件夹里的东西直接放到网站根目录(多数为www目录),而需要放到一个指定的文件夹,这里笔者以demo文件夹为例。因此,我们的访问路径就变为类似这样的地址:www.***.com/demo/。

对于这样的操作,webpack并没有提前帮我们做相关处理。如果我们采用默认配置,直接将打包好的dist文件夹里的东西上传到demo文件夹,将无法达到我们预期的效果。

要想实现将打包好的文件放到指定目录其实非常简单,只需要我们做一些相关配置即可,此配置不会影响本地开发。

此方法针对vue-cli以webpack初始化的模板,其它模板,未经测试。

特别说明:demo文件夹仅是例子,可自行根据需要修改为其它名字。

第一步,找到config文件夹里的index.js文件

  1. // 将'/'改成'/demo/'
  2. assetsPublicPath: '/demo/'

第二步,在路由配置文件里加上

  1. base: '/demo/'

完成了第二步,如果你的路由使用的是默认形式(即hash模式)则大功告成,无须进行下面步骤。

如果你想使用histroy模式,你需要在路由配置文件里加上

  1. mode: 'histroy',
  2. base: '/demo/'

除了上面这些,你还需要对服务器做相关配置,这里笔者以Apache为例

  1. # Apache代码,加入到网站的.htaccess里,没有该文件,自己可以新建一个(注意将最后一条规则里的demo修改成自己的目录名,否则只对demo文件夹有效)
  2. <IfModule mod_rewrite.c>
  3.   RewriteEngine On
  4.   RewriteBase /
  5.   RewriteRule ^index\.html$ - [L]
  6.   RewriteCond %{REQUEST_FILENAME} !-f
  7.   RewriteCond %{REQUEST_FILENAME} !-d
  8.   RewriteRule ^(demo|demo/.*)$ demo/index.html [L]
  9. </IfModule>

在进行vue项目开发的过程中,笔者建议路由使用默认形式(即hash模式),这样可以少踩很多坑,特别是在微信中。

欢迎分享你在使用Vue开发过程中遇到的问题。

shaw

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: