vue-skills

716 阅读3分钟

1、 状态共享

随着组件的细化,就会遇到多组件状态共享的情况,Vuex当然可以解决这类问题,不过就像Vuex官方文档所说的,如果应用不够大,为避免代码繁琐冗余,最好不要使用它,今天我们介绍的是vue.js 2.6新增加的Observable API ,通过使用这个api我们可以应对一些简单的跨组件数据状态共享的情况。

如下这个例子,我们将在组件外创建一个store,然后在App.vue组件里面使用store.js提供的store和mutation方法,同理其它组件也可以这样使用,从而实现多个组件共享数据状态。

首先创建一个store.js,包含一个store和一个mutations,分别用来指向数据和处理方法。

import Vue from "vue";

export const store = Vue.observable({ count: 0 });

export const mutations = {
  setCount(count) {
    store.count = count;
  }
};

然后在组件内里面引入这个store.js,在组件里面使用引入的数据和方法

<template>
  <div id="app">
    <img width="25%" src="./assets/logo.png">
    <p>count:{{count}}</p>
    <button @click="setCount(count+1)">+1</button>
    <button @click="setCount(count-1)">-1</button>
  </div>
</template>

<script>
import { store, mutations } from "./store";
export default {
  name: "App",
  computed: {
    count() {
      return store.count;
    }
  },
  methods: {
    setCount: mutations.setCount
  }
};
</script>

2、长列表性能优化

我们应该都知道vue会通过object.defineProperty对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要vue来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,那如何禁止vue劫持我们的数据呢?可以通过object.freeze方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了。

export default {
  data: () => ({
    users: {}
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
};

3、监听组件的生命周期

比如有父组件Parent和子组件Child,如果父组件监听到子组件挂载mounted就做一些逻辑处理,常规的写法可能如下:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
  this.$emit("mounted");
}

这里提供一种特别简单的方式,子组件不需要任何处理,只需要在父组件引用的时候通过@hook来监听即可,代码重写如下:

<Child @hook:mounted="doSomething"/>

当然这里不仅仅是可以监听mounted,其它的生命周期事件,例如:created,updated等都可以

4、优雅的处理vue项目异常

  • Vue.config.errorHandler
Vue.config.errorHandler = function (err, vm, info) {
  // 指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
  
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用  
}

全局处理异常的完整代码:

errorPlugin.js

/**
 * 全局异常处理
 * @param {
 * } error 
 * @param {*} vm 
 */
const errorHandler = (error, vm, info) => {
  console.error('抛出全局异常')
  console.error(vm)
  console.error(error)
  console.error(info)
}
let GlobalError = {
  install: (Vue, options) => {
  /**
   * 全局异常处理
   * @param {
   * } error 
   * @param {*} vm 
   */
    Vue.config.errorHandler = errorHandler
    Vue.mixin({
      beforeCreate() {
        const methods = this.$options.methods || {}
        Object.keys(methods).forEach(key => {
          let fn = methods[key]
          this.$options.methods[key] = function (...args) {
            let ret = fn.apply(this, args)
            if (ret && typeof ret.then === 'function' && typeof ret.catch === "function") {
              return ret.catch(errorHandler)
            } else { // 默认错误处理
              return ret
            }
          }
        })
      }
    })
    Vue.prototype.$throw = errorHandler
  }
}
export default GlobalError

使用

// 在入口文件中引入
import ErrorPlugin from './errorPlugin'
import Vue from 'vue'
Vue.use(ErrorPlugin)

5、移动端调试工具

1)vConsole

官方文档:github.com/Tencent/vCo…

使用方法:

  • a)多页面应用:
<script type="text/javascript” src="https://res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/vconsole/3.0.0/vconsole.min.js"></script>
<script>
//init vConsole
new VConsole();
</script>
//<script>
//var vconsole = new VConsole({
//    defaultPlugins: ['system', 'network', 'element', 'storage'], // 可以在此设定要默认加载的面板
//});
//</script>

  • b)单页应用

case1:

utils.js

// 加载控制台
export const loadScript = (url, callback) => {
    const script = document.createElement('script')
    script.onload = () => callback()
    script.src = url
    document.body.appendChild(script)
}

main.js

import { loadScript } from '@/assets/js/utils'
loadScript(
'https://res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/vconsole/3.0.0/vconsole.min.js',
() => {
    // eslint-disable-next-line
    new VConsole()
})

case2:

npm install vconsole

main.js

import VConsole from 'vconsole'
new VConsole();

2)eruda

官方文档:github.com/liriliri/er…

  • a)多页面应用:
<script type="text/javascript" src="https://cdn.bootcss.com/eruda/1.2.6/eruda.min.js"></script>
<script>
//直接使用不带任何参数的初始化方法init()会加载Eruda提供的全部面板,如果只需要部
//分面板需要在init()中带上配置参数。
eruda.init();
//eruda.init({
//    tool: ['console', 'elements']
//});
</script>
  • b)单页应用
npm install --save-dev eruda

eruda.js

;(function () {
    if (!/mdebug=true/.test(window.location.href)) return;
    var script = document.createElement('script')
    script.src = "https://cdn.bootcss.com/eruda/1.2.6/eruda.min.js"
    script.async = true
    document.getElementsByTagName('head')[0].appendChild(script)
    script.onload = function () {
        eruda.init()
    }
})()

main.js

import from './eruda.js' 

在需要调试的页面地址栏加上mdebug=true,即可开启

6、转场动画