1つの状態の共有
コンポーネントの洗練された、多成分の状態は、共有遭遇するVuex
もちろん、この問題を解決することができますが、としてVuex
公式文書は、アプリケーションが冗長コードが煩雑である避けるために十分な大きさでない場合、それは使用しないように最善である、と述べましたそれは、今日我々が2.6 vue.js新たに追加導入している観察可能なAPIを 私たちはいくつかの簡単なクロス・コンポーネントのデータが状態を共有するような状況に対処することができ、このAPIを使用することにより、。
この例に続いて、我々は、外部の部品を作成しstore
、その後、App.vue
アセンブリの内部に設けられstore.js使用store
とmutation
データ状態の複数を達成するために、他の成分は、そのまま使用することができることを同じようにメソッドをコンポーネントを共有しました。
最初store.jsを作成し、含むstore
とmutations
、データ及び処理方法を指すために使用されます。
"VUE"からインポートヴュー、エクスポートCONSTストア= Vue.observable({カウント:0})= {CONST変異をエクスポート setCount(カウント){ store.count =数えます。 } }; 复制代码
次いでれるApp.vue
データとメソッド内部に導入されたアセンブリで使用される、内部store.jsに導入
<テンプレート> の<divのid = "アプリ"> <IMG幅= "25%" SRC = "./資産/ logo.png"> <P>カウント:{{数}} </ P> <ボタン@クリック= "setCount(+ 1カウント)"> + 1 </ button>の <ボタン@クリックが= "setCount(カウント-1)"> - 1 </ボタン> </ div> </テンプレート> <スクリプト>輸入{店、アプリケーション"計算:「./store";exportのデフォルト{名":からの突然変異} { 数(){戻りstore.count。 } }、メソッド:{setCount:mutations.setCount } }; </ SCRIPT> <スタイル>复制代码
あなたはをクリックすることができ、オンラインでDEMO最終結果を見て
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); } }; 复制代码
另外需要说明的是,这里只是冻结了users
的值,引用不会被冻结,当我们需要reactive
数据的时候,我们可以重新给users
赋值。
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。
我做了一个测试,在线DEMO
<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 purgec***esult = purgecss.purge(); 复制代码
最终产生的purgec***esult
结果如下,可以看到多余的a
和ul
标签的样式都没了
image.png
4 作用域插槽
利用好作用域插槽可以做一些很有意思的事情,比如定义一个基础布局组件A,只负责布局,不管数据逻辑,然后另外定义一个组件B负责数据处理,布局组件A需要数据的时候就去B里面去取。假设,某一天我们的布局变了,我们只需要去修改组件A就行,而不用去修改组件B,从而就能充分复用组件B的数据处理逻辑,关于这块我之前写过一篇实际案例,可以点击这里查看。
这里涉及到的一个最重要的点就是父组件要去获取子组件里面的数据,之前是利用slot-scope
,自vue 2.6.0起,提供了更好的支持 slot
和 slot-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-bind
和v-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 函数式组件
函数式组件,即无状态,无法实例化,内部没有任何生命周期处理方法,非常轻量,因而渲染性能高,特别适合用来只依赖外部数据传递而变化的组件。
写法如下:
在
template
标签里面标明functional
只接受
props
值不需要
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.vuemounted() { this.$emit("mounted"); } 复制代码
这里提供一种特别简单的方式,子组件不需要任何处理,只需要在父组件引用的时候通过@hook
来监听即可,代码重写如下:
<Child @hook:mounted="doSomething"/>复制代码
当然这里不仅仅是可以监听mounted
,其它的生命周期事件,例如:created
,updated
等都可以,是不是特别方便~