vue3.0 beta已出,來快速實踐一下吧


vue3.0 beta已出,來快速實踐一下吧

本節源碼立即前往

前段時間尤大在嗶哩嗶哩直播了vue3的預覽,來簡單實踐一下吧

vue3的改變

  • 更小更快
  • 支持自定義渲染器
  • 響應式修改為基於Proxy的偵測
  • 深度結合typescript
  • 基於treeshaking優化
  • ...

創建項目😄

引入文件

克隆一個官方倉庫

git clone https://github.com/vuejs/vue-next.git

打開這個項目,下載一下依賴,然后編譯

npm i
npm run dev

編譯文件在vue-next\packages\vue\dist,可以把它復制出來放到我們創建的項目文件夾

vue-next\packages\vue\examples目錄下有官方的示例

腳手架創建項目

首先確保你的@vue/cli為最新版本 vue -V

image-20200516184602081

然后使用 vue create vue3demo創建一個vue項目,創建的時候勾選 vuex router

然后進入項目文件夾,命令行安裝插件vue add vue-next將項目升級到vue3,打開package.json可以發現都升級到了最新版本

image-20200517185314922

初始化你的第一個vue3程序⭐

實例化

為了體驗整個api的變化,我們先使用直接引入的方式體驗效果,新建一個index.html 引入vue.global.js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.global.js"></script>
</head>

<body>
</body>

</html>

然后我們新建一個盒子用來掛載vue實例,新建一個模板當做根節點

<body>
    <div id='app'>
    </div>
    <template id="root">
        <div>
        </div>
    </template>
</body>

實例化一個vue3vue3是按需引入,使用一個api之前需要先引入,通過createApp來實例化

<script>
    const {
        createApp
    } = Vue;
    const root = {
        template: '#root',
    }
    createApp(root).mount('#app');
</script>

setup

setup 函數是一個新的組件選項。作為在組件內使用 Composition API 的入口點。

vue3將更多的方法和數據在 setup函數中定義,這就是大家都覺得像react hook 的原因,其實實現的原理是不同的,只是寫法有點像;這樣做的目的就是為了更好的實現邏輯復用,具體會在后面舉例

與 2.x 版本生命周期相對應的組合式 API

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

setup最后返回所有的對象和方法,注意這里的msg不是響應式對象

const root = {
    template: '#root',
    // beforeCreate  created data和methods 
    setup() {
        console.log('vue init');
        const msg = "vue init";
        return {
            msg
        };
    },
}
<template id="root">
    <div>
        {{msg}}
    </div>
</template>

image-20200518113936084

ref和reactive

refreactive都是用來創建響應式對象的,接下來的案例都使用腳手架創建項目來進行測試

打開views/Home.vue文件,刪除掉無用的東西,首先引入ref, reactive

import { ref, reactive } from "vue";
export default {
  name: "Home",
  setup() {
    // 定義一個ref響應式對象
    const count = ref(0);
    // 如果要定義多個可以使用reactive
    const state = reactive({
      size: 36,
      color: "red"
    });
    // 定義一個方法
    const increment = () => {
      count.value++;
    };

    return {
      count,
      increment,
      state
    };
  }
};

在頁面中的使用和vue2是一樣的

<template>
  <div>
    <div>{{count}}</div>
    <button @click="increment">increment</button>
    <div :style="{fontSize:state.size+'px',color:state.color}">reactive</div>
  </div>
</template>

1

toRefs

上面reactive的導出和使用,必須state.key,如果想像vue2中的data一樣定義直接使用,可以使用 toRefs

引入 import { ref, reactive, toRefs } from "vue";,使用 toRefs返回展開對象,如果你不使用toRefs而直接返回對象,原對象的響應式將丟失。

return {
  count,
  increment,
  ...toRefs(state)
};

頁面中使用

<div :style="{fontSize:size+'px',color:color}">reactive</div>

image-20200518133238814

計算屬性和監聽器

我們來到about.vue中進行代碼編寫,首先引入需要使用的

import { reactive, watch, computed, toRefs, watchEffect } from "vue";

watchEffect 傳入一個函數並立即執行,如果函數里面使用了上面定義好的響應式對象,當對象發生變化時,會再次觸發這個函數

定義計算屬性和監聽器

export default {
  setup() {
    const state = reactive({
      num1: 1,
      //定義一個計算屬性
      num2: computed(() => state.num1 * 2)
    });
    
    // 如果響應性的屬性有變更,就會觸發這個函數,但他是惰性的
    watchEffect(() => {
      console.log(`effect 觸發了!${state.num1}`);
    });

    // 定義一個監聽器
    const stop = watch(state, (val, oldVal) => {
      console.log("watch ", oldVal.num1);
    });

    //數值增加方法
    const increment = () => state.num1++;

    // 停止監聽
    const stopwatch = () => stop();

    return {
      ...toRefs(state),
      stopwatch,
      increment
    };
  }
};

查看效果

3

dom操作

components文件夾下新建一個DomRef.vue文件,定義一個空的ref響應數據refdemo並返回,頁面中使用ref標簽來綁定這個數據,然后就可以通過操作這個響應數據來操作dom

<template>
  <div>
    <div ref="refdemo">domref</div>
    <input type="range" v-model="size" />
  </div>
</template>
<script>
import { ref, watch, onMounted } from "vue";
export default {
  setup() {
    // 定義空白ref作為Template ref操作 dom
    const refdemo = ref(null);
    const size = ref(24);
    // 監聽拖動 
    watch(size, (val, oldVal) => {
      refdemo.value.style.fontSize = size.value + "px";
    });
    return {
      refdemo,
      size
    };
  }
};
</script>

home組件中使用這個組件查看效果

<DomRef></DomRef>
...
import DomRef from "../components/DomRef";
...
components: {
  HelloWorld,
  DomRef,
},

看看效果

4

組件通信

和vue2的通信大同小異,新建ComDemo.vue,setup函數接受一個 propscontext 上下文

父組件>>子組件

  • 父組件觸發子組件事件
  • 父組件得到子組件屬性
  • props傳值
<template>
  <div>{{name}}</div>
</template>
<script>
import { inject } from "vue";
export default {
  props: {
    name: String
  },
  setup(props, context) {
    // setup中使用 prop
    console.log("props.name:" + props.name);
    // 供父組件測試
    const str = "我是子組件的str屬性";
    const talk = () => {
      console.log("我被父組件觸發了");
    };
    return {
      str,
      talk
    };
  }
};
</script>

來的Home.vue中使用這個組件,並給這個子組件綁定一個響應式的ref屬性

<ComDemo :name="'我是父組件傳值'" @talk="talk" ref="comdemo"></ComDemo>
import ComDemo from "../components/ComDemo";
...
components: {
  HelloWorld,
  DomRef,
},
 ...
setup() {
  // 定義一個ref響應式對象
  const comdemo = ref(null);
  onMounted(() => {
    //得到子組件的值
    console.log(comdemo.value.str);
    // 觸發子組件事件
    comdemo.value.talk();
  });
  return {
  	...
    comdemo
  };
}

看看效果

image-20200519162552547

子組件>>父組件

綁定一個方法給子組件

<ComDemo :name="'我是父組件傳值'" @talk="talk" ref="comdemo"></ComDemo>
...
setup() {
const talk = e => {
  console.log(e);
};
...
return {
 ...
  talk,
  comdemo
};
...

ComDemo.vue

setup(props, context) {
  ...
  // setup中觸發父組件事件
  context.emit("talk", "我是子組件 我觸發你了");
  ...
  return {
    str,
    talk
  };
}

效果

image-20200519163223419

inject和provide

這個和vue2使用一樣

父組件定義

import { provide } from "vue";
...
provide("injectmsg", "provide talk");

后代組件使用

import { inject } from "vue";
...
const injectmsg = inject("injectmsg");
console.log("injectmsg :>> ", injectmsg);

組合式api示例❤️

前面說到 Composition API的好處,這來舉一個例

放一個尤大神的demo,這是一段鼠標操作的功能代碼,我們自己還需要編寫一個功能來實現結合

const useMouse = () => {
  const state = reactive({
    x: 0,
    y: 0
  });
  const update = e => {
    state.x = e.pageX;
    state.y = e.pageY;
  };
  onMounted(() => {
    window.addEventListener("mousemove", update);
  });
  onUnmounted(() => {
    window.removeEventListener("mousemove", update);
  });
  return toRefs(state);
};

我們再寫一個鍵盤方法,記錄每次用戶按下鍵盤

// 監控鍵盤事件
const useKeyBoard = () => {
  const status = ref(false);
  const update = () => {
    status.value = !status.value;
  };
  onMounted(() => {
    window.addEventListener("keypress", update);
  });
  onUnmounted(() => {
    window.removeEventListener("onkeydown", update);
  });
  return {
    status
  };
};

我們來到 HelloWorld.vue組件中使用這兩個方法

<template>
  <div>{{status?`${x}-${y}`:`${y}-${x}`}}</div>
</template>

<script>
import { reactive, onMounted, onUnmounted, toRefs, ref } from "vue";
// 返回鼠標位置
const useMouse = () => {
  const state = reactive({
    x: 0,
    y: 0
  });
  const update = e => {
    state.x = e.pageX;
    state.y = e.pageY;
  };
  onMounted(() => {
    window.addEventListener("mousemove", update);
  });
  onUnmounted(() => {
    window.removeEventListener("mousemove", update);
  });
  return toRefs(state);
};
// 監控鍵盤事件
const useKeyBoard = () => {
  const status = ref(false);
  const update = () => {
    status.value = !status.value;
  };
  onMounted(() => {
    window.addEventListener("keypress", update);
  });
  onUnmounted(() => {
    window.removeEventListener("onkeydown", update);
  });
  return {
    status
  };
};
export default {
  name: "HelloWorld",
  setup() {
    return {
      ...useMouse(),
      ...useKeyBoard()
    };
  }
};
</script>

我們在頁面中顯示鼠標方位,當我們按下任何按鍵的時候,這個顯示顛倒

看下效果

5

vuexvuerouter💥

vuexvuerouter在實例化方式上有了一點區別,分別使用 createStorecreateRouter進行實例化

使用vuex

打開vue3demo\src\store\index.js文件

import Vuex from 'vuex'

export default Vuex.createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
      console.log('當前count:',state.count);
    }
  },
  actions: {},
  modules: {}
});

新建一個 RouterAndVuex.vue組件

<template>
  <div>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore();
    const count = store.state.count;
    console.log("vuex >>", count);
    const increment = () => {
      // mutations
      store.commit("increment");
    };
    return {
      increment,
    };
  }
};
</script>

看看效果

6

使用vuerouter

<template>
  <div>
    <button @click="increment">increment</button>
    <button @click="gotoAbout">about</button>
  </div>
</template>

<script>
import { useStore } from "vuex";
import { useRouter } from "vue-router";
export default {
  setup() {
    //   使用vuex
    const store = useStore();
    const count = store.state.count;
    console.log("vuex >>", count);
    const increment = () => {
      // mutations
      store.commit("increment");
    };
    // 使用vue-router
    const router = useRouter();
    const gotoAbout = () => {
      router.push("About");
    };
    return {
      increment,
      gotoAbout
    };
  }
};
</script>

看看效果

7


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM