vue3.0已经发布啦~
记录一下自己创建vue3.0项目的学习过程。
更新的一些东西
- Object.defineProperty => Proxy
- vdom 静态标记更加强大
- Composition API
- vite
初始项目
一改vue2.x使用vue-cli, vue3.0基于vite去创建项目:
1 2 3 4
| npm init vite-app <project-name> cd <project-name> npm install npm run dev
|
项目结构
1 2 3 4 5 6 7 8 9 10 11 12
| ├── index.html ├── package.json ├── public │ └── favicon.ico └── src ├── App.vue ├── assets │ └── logo.png ├── components │ └── HelloWorld.vue ├── index.css └── main.js
|
index.html/main.js
可以看到 main.js的引用写了type="module"
,利用浏览器的自带的import机制;
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vite App</title> </head>
<body> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body>
</html>
|
- main.js 初始实例不再是
new vue(option)
,改为了createApp(App)
Vue.prototype
扩展方法改为了app.config.globalProperties
- 还有一个需要注意的地方,vue3.0 setup内部不支持this,像vue2.x里可以 Vue.prototype扩展一些全局方法,在页面使用直接this就可以访问,在
Composition API
里面已经不能这么玩了😂。
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { createApp } from 'vue' import App from './App.vue' import './assets/index.css' import * as config from './utils/config_globalProperties.ts'
const app = createApp(App);
Object.keys(config).forEach(ele => { app.config.globalProperties[ele] = config[ele] });
app.mount('#app');
|
Composition API
1.setup
组件选项创建后在组件创建之前执行的组件选项,它用作组合API的入口点,相当于beforCreated()
、created()
;
vue2.x 在写页面的时候,script
里面,是写的option Api
导出一个对象,对象里面就是data
、methods
、mounted
…..
现在直接一个setup
函数,在setup
里面把数据return给template;
下面是官网的例子,非常清晰:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!-- MyBook.vue --> <template> <div>{{ readersNumber }} {{ book.title }}</div> </template>
<script> import { ref, reactive } from 'vue'
export default { setup() { const readersNumber = ref(0) const book = reactive({ title: 'Vue 3 Guide' })
// expose to template return { readersNumber, book } } } </script>
|
2.ref
是对基础数据进行双向绑定的Api,经过ref过的数据,需要通过value属性拿到值;
1 2 3 4 5 6 7 8
| import { ref } from "vue";
...
const a = ref(0); console.log(a.value)
...
|
3.reactive
引用类型的数据结构使用reactive
,使用reactive
有一个要注意的点,最好不要对reactive过的对象做结构操作,会使reactive过的对象里面的基本数据类型失去双向绑定,对解构的数据做更改是不会再去更新reactive的这个对象了。建议对reactive的数据慎用解构,直接操作reactive的对象,免得导致一些不必要的坑;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { reactive } from "vue";
...
let obj = reactive({ a: "a", b: "b", c: { c1: "c1", }, }); obj.a = "我是a呀"; obj.b = "我是b呀"; obj.c.c1 = "我是c1呀";
let { a, c } = obj; a = "我是被解构的a"; c.c1 = "我是被解构的c1";
console.log(obj); console.log(a); console.log(c);
...
|
4.Lifecycle Hooks 生命周期
composition Api
里面生命周期也有所变化,beforeCreate
、created
被setup替代,其他生命周期均多了on
:
beforeCreate
-> use setup()
created
-> use setup()
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeUnmount
-> onBeforeUnmount
unmounted
-> onUnmounted
errorCaptured
-> onErrorCaptured
renderTracked
-> onRenderTracked
renderTriggered
-> onRenderTriggered
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = { setup() { onMounted(() => { console.log('mounted!') }) onUpdated(() => { console.log('updated!') }) onUnmounted(() => { console.log('unmounted!') }) } }
|
5.Provide / Inject
其实这个跟React.context
很类似,都是为了解决组件嵌套多层props传值的问题(避免数据多层传递的繁琐性),在父级把需要传递的数据通过Provide
包裹,在需要用到数据的子组件使用Inject
注入即可使用,在子级修改Inject
后的值父级的值是动态改变的。
app.vue 父级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <img alt="Vue logo" src="./assets/logo.png" /> <HelloWorld /> </template>
<script> import HelloWorld from "./components/HelloWorld.vue"; import { provide, ref } from "vue"; export default { components: { HelloWorld, }, setup() { let msg = ref("Hello Vue 3.0 + Vite");
// 提供数据 provide inject // vue3.0 一改组件 // 类似于 React.context(), myContext.provider myCcontent.consumer provide("msg", msg);
return { msg }; }, }; </script>
|
helloworld.vue 子级中使用
1 2 3 4 5 6
| setup() { const msg = inject("msg");
return { msg } },
|
6.自己搭建的小项目里暂时只使用到了:
- ref
- reactive
- provide inject
helloword.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <h1>{{ msg }}</h1> <p>{{ obj.a }}</p> <p>{{ obj.b }}</p> <p>{{ obj.c && obj.c.c1 }}、{{ obj.c && obj.c.c2 }}</p> <button @click="addCount">count is: {{ count }}</button> </template>
<script> import helloworld from "./helloworld"; export default { setup() { // helloworld() 为逻辑代码,可以单独拎出去,这也是composition Api的一大好处,逻辑代码可以高度解耦,可复用性更强! return Object.assign({}, helloworld()); }, }; </script>
|
helloworld.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import { ref, reactive, inject } from "vue"; import { $log, $info, $test } from "../modules-index";
const helloworld = ():object => { const msg = inject("msg");
const count = ref(0); const addCount = function () { count.value++; $log(count.value, "count:"); };
const obj = reactive({ a: "a", b: "b", c: { c1: "c1", c2: "c2", }, });
obj.a = "我是a呀"; obj.b = "我是b呀"; obj.c.c1 = "我是c1呀";
let { a, c } = obj; a = "我是被解构的a"; c.c1 = "我是被解构的c1";
$log(obj); $log(a, 'a:'); $log(c, 'c:');
$log($info, "测试引用:"); $test();
return { msg, count, addCount, obj } };
export default helloworld;
|
代码
以上示例的代码放在了GitHub上: https://github.com/LLDLLY/vue3.0-init.git