vue踩坑记录(持续更新)

110 阅读2分钟

个人的Vue学习和使用踩坑记录,持续更新中,欢迎指正。

  1. import导入组件或@import导入样式时,@作为别名表示src目录。对于scss样式,需要在前面加波浪号,即使用~@才能使用该别名。

  2. vue.config.js默认的打包相关的配置都在里面,比如webpack相关设置。

  3. 本地调试时需要访问外部链接或接口时会有跨域问题,此时在vue.config.js下配置devServer.proxy代理即可绕过跨域问题。如下配置对api开头的接口代理到https://www.realapi.com:

    devServer: {
     proxy: {
       '/api': {
         target: 'https://www.realapi.com',
         changeOrigin: true
       }
     }
    

}


4. pointer-events: none;  /* 禁止鼠标点击 */

5. `$router.back()`和`$router.go(-1)`都能返回上一页,但是`$router.go(-1)`原页面表单中的内容会丢失。

6. 自定义组件在被使用时,最终渲染出来的dom上出现了名为组件名的节点(如ComponentTest组件显示成了component-test,而不是自带的html节点div)。

原因在于组件的导入方式import和组件的导出方式export是否对应,要理解importexport的使用细节。


---
*importexport科普开始*

假设现在有下面这样一个index.js:
```javascript
var str = 'Hello World';
export str;
export var count = 4;
export default {
 slogan: "fight",
 time: 12
};

导入时这样导入:

import {count} from './index.js';
import who from './index.js';
console.log('nested-export', who, count);

这个时候count和who都能如预期般获取并打印出一个对象和数字4。但如果反过来像这样:

import count from './index.js';
import {who} from './index.js';
console.log('nested-export', who, count);

打印出来的结果就是nested-export undefined {slogan: 'fight', time: 12}。也就是说,who并没有指向任何对象,而count指向了index.js中导出的default对象。

出现这样的结果原因在于,

import count from './index.js';import {default as count} from './export';的简写 import {who} from './index.js';import {who as who} from './index.js';的简写

index.js中导出的对象中没有名为who的对象,import时也就无法解构赋值给who,所以who是undefined。

import和export科普结束


说回Vue组件,假设现在有ComponentTest组件,大部分情况下,components/ComponentTest/index.vue文件内使用的导出方式是export default {components: ,methods:, ...}, 外部需要导入这个组件时例举两种写法:

写法1. import ComponentTest from '@/components/ComponentTest'; 这种写法,定义的ComponentTest指向的是ComponentTest/index.vue中导出的default对象,所以ComponentTest的内部模板能被解析成html自带的标签。 写法2. import { ComponentTest } from '@/components/ComponentTest'; 通过我们对import和export的科普一节我们知道,这种写法中ComponentTest是undefined,神奇的是编译和运行都不会报错,最终渲染出来的dom上空有一对<component-test></component-test>标签,并不会有ComponentTest的功能。

但是有一种情况下,是需要用写法2而非写法1。那就是在使用组件合并导出的时候,比如在@/components/index.js中有如下的代码:

export { default as ComponentA } from './ComponentA';
export { default as ComponentTest } from './ComponentTest';

需要注意一下,export { default as ComponentTest } from './ComponentTest';的作用相当于

import { default as ComponentTest } from './ComponentTest'; 
export ComponentTest;

也就是说,index.js的导出对象中,包含一个key为ComponentTest的ComponentTest对象,所以在从index.js中导入组件时,要使用以上的写法2,即:

import { ComponentTest } from '@/components';
  1. window.location.search和window.location.hash的区别 location.search是第一个问号(含问号)到第一个井号之间的部分,location.hash是第一个井号(含井号)到链接结束的部分。(一个链接中,可能会有多个问号,即如下例子所示,第一个问号后面跟的是针对html页面的参数,第二个问号后面跟的是针对该路由的参数;井号目前只发现一个的情况,如果有多个井号,对于SPA页面路由会混乱 或者 以遇到的第一个井号为准?)

    假设有这样一个链接 http://www.hello.com/index.html?userid=123&phone=6553525#/user/findpwd?time=156534456 。window.location.search的值为?userid=123&phone=6553525,window.location.hash的值为#/user/findpwd?time=156534456

    对于VueRouter,this.$router.query取到的其实就是window.location.hash对应的字符串转换成的js对象。

  2. 代码更新时出现了A删除了某一个文件夹及其中的文件,但是自己拉到时文件夹还在的情况,此时这个文件夹无法被访问更无法删除。解决办法是关掉VSCode。。。应该是VSCode进程锁住了该目录,外部git工具更新时无法删除掉它。

  3. $router.push$router.replace的区别以及踩到的坑 $router.push会把导航堆栈累加,$router.replace会替换导航堆栈最上层的页面为目标页面。对于这样的情形:A push B push C,此时从C后退会依次回到B和A,但如果是A push B replace C,此时从C后退会直接回到A。 坑:页面流转时为了让子页面能方便的取到用户id、token等数据,在query中带上了用户token等公共参数,在VuewRouter的导航守卫上加了钩子,类似这样:

    router.beforeEach((to, from, next) => {
      if (from.query.userid) {
         next({
            path: to.path,
            query: {
               ...to.query,
               token: from.query.token,
               userid: from.query.userid
            }
         });
      } else {
         next();
      }
    });
    

    这样一来,子页面也能通过query取到用户id、token等数据了,但是由于beforeEach钩子中带参数的行为,其实是相当于是对页面做了重定向,这样钩住会带来以下问题:

    • 调用$router.push$router.replace会报错Uncaught (in promise) Error: Redirected when going from “abcdefg” to “hijklmn” via a navigation guard.,这个错误并不会导致跳转失败,如果要规避报错也很简单,使用如下代码hook住原有的push和replace方法即可:
      const originalPush = router.push;
      router.push = function(...args) {
      return originalPush.call(this, ...args).catch(failure => {
         if (!isNavigationFailure(failure, NavigationFailureType.redirected)) {
            // beforeEach路由守卫会抛出异常,详情见 https://github.com/vuejs/vue-router/issues/3221
            console.error(failure);
         }
      });
      };
    
      const originalReplace = router.replace;
      router.replace = function(...args) {
      return originalReplace.call(this, ...args).catch(failure => {
         if (!isNavigationFailure(failure, NavigationFailureType.redirected)) {
            console.error(failure);
         }
      });
      };
    
    • $router.replace带来的导航堆栈行为变得与$router.push一样了