Vue3.0極簡使用

前言

vue3.0已經發布正式版,遲早都要學,趕早不趕晚。vue

本文全部文字出自個人vue3練手倉庫 GitHubreact

Reactivity API

一組能夠將UI 和 數據處理邏輯 分離的API。 入口函數setup();git

ref() && reactive()

這兩個函數,均可以把數據,變成響應式的。即,數據改變 驅動 視圖(UI)改變。 其中。ref通常對簡單數據類型進行包裝,reactive對引用數據類型進行包裝。github

先看下ref的例子api

<template>
    <button @click="addCnt">count is: {{ cnt }}</button>
</template>

<script>
import { ref } from 'vue';
export default {
    name: 'Ref',
    // setup函數 是組合API(composition API) 的入口函數
    setup() {
        // 定義 變量/state。 注意ref()首字母小寫,不是Ref。
        let cnt = ref(0); // ref只能監聽簡單類型數據的變化,不能監聽複雜類型(對象/數組),複雜類型請用reactive()。

        // 定義 函數(方法)
        const addCnt = () => {
            // 注意必須加value
            cnt.value++;
        };

        // 在組合API中定義的變量/方法,想要在外部使用,必須return暴露出去
        return { cnt, addCnt };
    },
};
</script>
這是一個簡單的 加法器 demo。咱們用ref聲明一個可響應狀態cnt, 以及一個數據處理邏輯函數addCnt, 
setup()要求將狀態和方法返回,才能在模板裏使用。

複製代碼

再來看reactive的例子,實現一個TODO list demo數組

<template>
    <form>
        姓名:<input type="text" v-model="state.name">
        年齡:<input type="text" v-model="state.age">
        <input type="submit" @click="submit"></input>
    </form>
    <ol class="ol">
        <li v-for="(item, index) in state.students" :key="index" @click="delStu(index)">
            {{ item.name }} -- {{ item.age }}
        </li>
    </ol>
</template>

<script>
import { reactive } from 'vue'; // 注意首字母小寫
export default {
    name: 'Reactive',

    // 入口函數
    setup() {
        // 聲明幾個變量,用reactive監聽變化。
        let state = reactive({
            students: [
                {
                    name: '張三',
                    age: 11,
                },
                {
                    name: '李四',
                    age: 21,
                },
            ],
            name: '',
            age: '',
        });

        // 添加一個學生
        let submit = (e) => {
            e.preventDefault();
            state.students.push({
                name: state.name,
                age: state.age,
            });
            state.name = '';
            state.age = '';
        };

        // 刪除一個學生
        let delStu = (index) => {
            state.students.splice(index, 1);
        };
        return { state, submit, delStu };
    }
};
</script>
複製代碼

混合使用options api和composition API

composition API 固然是能夠和之前vue2.x的Options API那種寫法混用的。 實際上,composition API也叫注入API,是將setup中暴露的變量和方法注入到data()和methods中去。markdown

<template>
    <div>
        {{ count }}
        <button @click="logCount">點擊Count</button>
    </div>
    <div>
        {{ cnt }}
        <button @click="logCnt">點擊Cnt</button>
    </div>
</template>

<script>
import { ref } from 'vue';
export default {
    name: 'Mix',
    data() {
        return {
            count: 1,
        };
    },
    methods: {
        logCount() {
            alert(this.count);
        }
    },
    // Vue2.x的寫法叫作 Options API寫法
    // 本🌰可見,組合API和Options API能夠混用。
    // 且實際上,組合API(也叫注入API)是將其中的變量和方法注入到data()和methods中去
    setup() {
        let cnt = ref(5);
        let logCnt = () => {
            alert(cnt.value); // 注意ref監聽的對象,在js中使用要加.value。
        };
        return { cnt, logCnt };
    }

};
</script>

複製代碼

isRef() && isReactive()

如何區分一個數據或者狀態,是經過ref仍是reactive包裝的呢? 能夠經過isRef 和 isReactive 兩個方法進行判斷。函數

<template>
    <button @click="log"> 按鈕 </button>
</template>

<script>
import { ref, reactive, isRef, isReactive } from 'vue';
export default {
    name: 'Which',
    setup() {
        let age = ref(18);
        let state = reactive({
            age: 11
        });

        const log = () => {
            console.log('age is ref ? ', isRef(age)); // true
            console.log('age is reactive ? ', isReactive(age)); // false
            console.log('state is ref ? ', isRef(state)); // false
            console.log('state is reactive ? ', isReactive(state)); // true
        };

        return { age, log };
    },
};
</script>
複製代碼

在這個例子裏,age是經過ref包裝的,state是經過reactive包裝的,能夠經過isRef和isReactive區分。oop

shallowRef() && shallowReactive()

默認狀況下,ref和reactive包裝的數據都是 遞歸監聽的,於是能夠遞歸響應。 可是遞歸監聽對性能是有影響的。 那麼,假設要監聽的數據數據量很大,且嵌套結構特別深,若是想要只對第一層數據監聽,這種狀況下,就可使用shallowReactive()。性能

<template>
    <div>
        <div>{{state.age}}</div>
        <div>{{state.a.v}}</div>
        <div>{{state.a.b.v}}</div>
    </div>
    <button @click="log">按鈕</button>
</template>

<script>
import { reactive, shallowReactive, shallowRef } from 'vue';
export default {
    name: 'Recurse',
    setup() {
        // 只須要將reactive改爲shallowReactive,就能夠非遞歸監聽
        // 通常狀況下,使用默認的遞歸監聽便可,只有傳入的數據量較大的時候,才考慮非遞歸監聽
        let state = shallowReactive({
            a: {
                v: 1,
                b: {
                    v: 2,
                }
            },
            age: 15
        });

        const log = () => {
            // 注意觀察 註釋掉下面這句話 和 不註釋下面這句話 的區別。
            // state.age = 16; // 只有age修改能夠引發UI變化,若age不修改,內層數據修改,UI不變;若age和內存數據都修改,UI都變,是由於age的變化帶動了內層數據UI的響應
            state.a.v = 'a';
            state.a.b.v = 'b';

            console.log('111: ', state);
            console.log('111: ', state.a);
            console.log('111: ', state.a.b);
        };
        return { state, log };
    },
};
</script>

複製代碼

toRaw() && markRaw()

仍是上面那個問題,ref和reactive包裝後,數據變動都是實時反映到UI上的,若是監聽的數據數據量很大,那麼,有可能 是對性能有所影響的。

若是不想對某些數據或狀態的修改,都進行UI上的實時響應變化,該怎麼辦呢? toRaw 和 markRaw也許能夠幫到你。

toRaw 和 markRaw的區別是:toRaw是能夠把某個可響應數據/狀態,反取到原始值,修改原始值,UI是不會實時變化的; 而markRaw則是直接將數據或狀態聲明爲不可響應的,則後面,即便加了ref、reactive這樣的包裝,UI也不會再響應數據的變動。

先來看看toRaw

<template>
    <div>
        {{ state.name}} -- {{ state.age }}
        <button @click="log">按鈕</button>
    </div>
</template>

<script>
import { reactive, toRaw } from 'vue'; // 注意首字母小寫
export default {
    name: 'ToRaw',

    // toRaw的做用:由於ref/reactive每次修改都更新UI,性能消耗大,若某些操做不須要UI及時更新,能夠經過toRaw拿到原始數據
    // 對原始數據進行修改,這樣UI就不會更新,性能就行了。
    // (固然也能夠像下面那樣,在定義ref/reactive的時候,就把原始變量user單獨拿出去聲明,直接修改user,跟修改userOld是同樣的))
    setup() {
        let user = {
            name: 'zs',
            age: 12,
        };
        let state = reactive(user);
        console.log('user === reactive(user): ', user === state); // false。 他們是引用關係

        let userOld = toRaw(state);
        console.log('user === toRaw(state): ', user === userOld); // true.

        let log = () => {
            // 改變原始數據,UI天然不會響應。(不過由於是引用關係,state.name其實已經變成lisi了。)
            user.name = 'lisi';
            console.log('111: ', state);
        };

        return { state, log };
    }
};
</script>
複製代碼

再來看看markRaw

<template>
    <div>
        {{ state.name}} -- {{ state.age }}
        <button @click="log">按鈕</button>
    </div>
</template>

<script>
import { reactive, markRaw } from 'vue'; // 注意首字母小寫
export default {
    name: 'MarkRaw',

    setup() {
        let user = {
            name: 'zs',
            age: 12,
        };

        // 注意加 和 不加markRaw 區別。有了它,UI永不響應數據的變化。(雖然數據自己已經變了)
        markRaw(user);

        // 即便後面再用reactive包裝改變量,UI也不響應數據變動。
        let state = reactive(user);

        let log = () => {
            state.name = 'lisi';
            console.log('111: ', state);
        };

        return { state, log };
    }
};
</script>
複製代碼

後記

還有不少特性,要手擼, 該倉庫 持續更新中,歡迎star~~~

GitHub

相關文章
相關標籤/搜索