起步:
配置开发环境
Vue cli
// 安装或者升级
npm install -g @vue/cli
# OR
yarn global add @vue/cli
// 保证 vue cli 版本在 4.5.0 以上
vue --version
// 创建项目
vue create my-project
- ref()语法
<template>
<h1>{{count}}</h1>
<h1>{{double}}</h1>
<button @click="increase">+1</button>
</template>
import { ref } from "vue"
setup() { // setup在props、data、生命周期之前,无法访问this
// ref 是一个函数,它接受一个参数,返回的就是一个 响应式对象
const count = ref(0)
const double = computed(() => {
return count.value * 2
})
const increase = () => {
count.value++
}
// return之后可以在template中使用了
return {
count,
increase,
double
}
}
-
reactive函数
import { ref, computed, reactive, toRefs } from 'vue' interface DataProps { count: number; double: number; increase: () => void; } setup() { const data: DataProps = reactive({ count: 0, increase: () => { data.count++}, double: computed(() => data.count * 2) }) const refData = toRefs(data) return { ...refData } }
- 生命周期
在setup中使用
- beforeCreate -> 不需要
- created -> 不需要
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeUnmount -> onBeforeUnmount
- unmounted -> onUnmounted
- errorCaptured -> onErrorCaptured
- renderTracked -> onRenderTracked
- renderTriggered -> onRenderTriggered
setup() { onMounted(() => { console.log('mounted') }) onUpdated(() => { console.log('updated') }) onRenderTriggered((event) => { console.log(event) }) }
-
watch
// watch 简单应用 watch(data, () => { document.title = 'updated ' + data.count }) // watch 多个值,返回的也是多个值的数组,两个参数,代表新的值和旧的值 watch([title, data], (newValue, oldValue) => { console.log(newValue); console.log(oldValue); document.title = 'update' + title.value + data.count; });
-
模块化开发
// 将组件内逻辑抽象成可复用的函数 function useMouseTracker() { const x = ref(0) const y = ref(0) const updatePosition = (event: MouseEvent) => { x.value = event.clientX y.value = event.clientY } onMounted(() => { document.addEventListener('click', updatePosition) }) onUnmounted(() => { document.removeEventListener('click', updatePosition) }) return { x, y } } export default useMouseTracker
这种实现方式优点
- 可以设置别名,避免命名冲突
- 可以清楚知道值的来源,有什么作用
- 逻辑可以脱离组件,只有逻辑代码在里边
-
Teleport
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。
属性to接受一个css query selector 作为参数告诉teleport应该在哪个标签下边
<template> <teleport to="#modal"> <div id="center"> <h1>this is a modal</h1> </div> </teleport> </template>
props是一个响应式对象,
context
是一个普通的 JavaScript 对象,它暴露三个组件的 property:attrs、slots、emit,context
是普通的js对象,所以可以使用ES6解构export default { setup(props, { attrs, slots, emit }) { ... } }
-
定义一个异步组件,在 setup 返回一个 Promise
<template> <h1>{{result}}</h1> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ setup() { return new Promise((resolve) => { setTimeout(() => { return resolve({ result: 42 }) }, 3000) }) } }) </script>
在 App 中使用
<Suspense> <template #default> <async-show /> </template> <template #fallback> <h1>Loading !...</h1> </template> </Suspense>
-
全局api修改
import Vue from 'vue' import App from './App.vue' Vue.use(/* ... */) Vue.mixin(/* ... */) Vue.component(/* ... */) Vue.directive(/* ... */) Vue.prototype.customProperty = () => {} new Vue({ render: h => h(App) }).$mount('#app')
Vue3 的修改
import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // 这个时候 app 就是一个 App 的实例,现在再设置任何的配置是在不同的 app 实例上面的,不会像vue2 一样发生任何的冲突。 app.use(/* ... */) app.mixin(/* ... */) app.component(/* ... */) app.directive(/* ... */) // 当配置结束以后,我们再把 App 使用 mount 方法挂载到固定的 DOM 的节点上。 app.mount(App, '#app')
vue2和vue3 v-model
// vue2 <input v-model="val"/> <input type="text" :value="val" @input="val = $event.target.value"/> // vue3 compile 以后的结果 <my-Component v-model="foo" /> h(Comp, { modelValue: foo, 'onUpdate:modelValue': value => (foo = value) }) <ChildComponent v-model="pageTitle" /> <!-- 简写: --> <ChildComponent :modelValue="val" @update:modelValue="pageTitle = $event" />