7个有用的Vue开发技巧

1 状态共享

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

以下这个例子,咱们将在组件外建立一个store,而后在App.vue组件里面使用store.js提供的storemutation方法,同理其它组件也能够这样使用,从而实现多个组件共享数据状态。css

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

import Vue from "vue";

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

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

复制代码

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

<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>

<style>
复制代码

你能够点击在线DEMO查看最终效果java

2 长列表性能优化

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

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

另外须要说明的是,这里只是冻结了users的值,引用不会被冻结,当咱们须要reactive数据的时候,咱们能够从新给users赋值。ios

export default {
  data: () => ({
    users: []
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  },
  methods:{
    // 改变值不会触发视图响应
    this.users[0] = newValue
    // 改变引用依然会触发视图响应
    this.users = newArray
  }
};
复制代码

3 去除多余的样式

随着项目愈来愈大,书写的不注意,不天然的就会产生一些多余的css,小项目还好,一旦项目大了之后,多余的css会愈来愈多,致使包愈来愈大,从而影响项目运行性能,因此有必要在正式环境去除掉这些多余的css,这里推荐一个库purgecss,支持CLI、JavascriptApi、Webpack等多种方式使用,经过这个库,咱们能够很容易的去除掉多余的css。axios

我作了一个测试,在线DEMOapi

<h1>Hello Vanilla!</h1>
<div>
  We use Parcel to bundle this sandbox, you can find more info about Parcel
  <a href="https://parceljs.org" target="_blank" rel="noopener noreferrer">here</a>.
</div>
复制代码
body {
  font-family: sans-serif;
}
a {
  color: red;
}
ul {
  li {
    list-style: none;
  }
}
复制代码
import Purgecss from "purgecss";
const purgecss = new Purgecss({
  content: ["**/*.html"],
  css: ["**/*.css"]
});
const purgecssResult = purgecss.purge();
复制代码

最终产生的purgecssResult结果以下,能够看到多余的aul标签的样式都没了性能优化

4 做用域插槽

利用好做用域插槽能够作一些颇有意思的事情,好比定义一个基础布局组件A,只负责布局,无论数据逻辑,而后另外定义一个组件B负责数据处理,布局组件A须要数据的时候就去B里面去取。假设,某一天咱们的布局变了,咱们只须要去修改组件A就行,而不用去修改组件B,从而就能充分复用组件B的数据处理逻辑,关于这块我以前写过一篇实际案例,能够点击这里查看。

这里涉及到的一个最重要的点就是父组件要去获取子组件里面的数据,以前是利用slot-scope,自vue 2.6.0起,提供了更好的支持 slotslot-scope 特性的 API 替代方案。

好比,咱们定一个名为current-user的组件:

<span>
  <slot>{{ user.lastName }}</slot>
</span>
复制代码

父组件引用current-user的组件,但想用名替代姓(老外名字第一个单词是名,后一个单词是姓):

<current-user>
  {{ user.firstName }}
</current-user>
复制代码

这种方式不会生效,由于user对象是子组件的数据,在父组件里面咱们获取不到,这个时候咱们就能够经过v-slot 来实现。

首先在子组件里面,将user做为一个<slot>元素的特性绑定上去:

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>
复制代码

以后,咱们就能够在父组件引用的时候,给v-slot带一个值来定义咱们提供的插槽 prop 的名字:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>
复制代码

这种方式还有缩写语法,能够查看独占默认插槽的缩写语法,最终咱们引用的方式以下:

<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>
复制代码

相比以前slot-scope代码更清晰,更好理解。

5 属性事件传递

写太高阶组件的童鞋可能都会碰到过将加工过的属性向下传递的状况,若是碰到属性较多时,须要一个个去传递,很是不友好而且费时,有没有一次性传递的呢(好比react里面的{...this.props})?答案就是v-bindv-on

举个例子,假若有一个基础组件BaseList,只有基础的列表展现功能,如今咱们想在这基础上增长排序功能,这个时候咱们就能够建立一个高阶组件SortList

<!-- SortList  -->
<template> <BaseList v-bind="$props" v-on="$listeners"> <!-- ... --> </BaseList> </template>

<script>
  import BaseList from "./BaseList";
  // 包含了基础的属性定义
  import BaseListMixin from "./BaseListMixin";
  // 封装了排序的逻辑
  import sort from "./sort.js";

  export default {
    props: BaseListMixin.props,
    components: {
      BaseList
    }
  };
</script>
复制代码

能够看到传递属性和事件的方便性,而不用一个个去传递

6 函数式组件

函数式组件,即无状态,没法实例化,内部没有任何生命周期处理方法,很是轻量,于是渲染性能高,特别适合用来只依赖外部数据传递而变化的组件。

写法以下:

  1. template标签里面标明functional
  2. 只接受props
  3. 不须要script标签
<!-- App.vue -->
<template> <div id="app"> <List :items="['Wonderwoman', 'Ironman']" :item-click="item => (clicked = item)" /> <p>Clicked hero: {{ clicked }}</p> </div> </template> <script> import List from "./List"; export default { name: "App", data: () => ({ clicked: "" }), components: { List } }; </script> 复制代码
<!-- List.vue 函数式组件 -->
<template functional> <div> <p v-for="item in props.items" @click="props.itemClick(item);"> {{ item }} </p> </div> </template>
复制代码

7 监听组件的生命周期

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

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

// Child.vue
mounted() {
  this.$emit("mounted");
}
复制代码

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

<Child @hook:mounted="doSomething"/>
复制代码

固然这里不只仅是能够监听mounted,其它的生命周期事件,例如:createdupdated等均可以,是否是特别方便~

参考连接:

相关文章
相关标签/搜索