1. 创建Vue实例
Vue3使用API一律是函数式风格所以和new告别了。
// Vue3.0 import {createApp} from 'vue' createApp(App).use(router).use(store).mount('#app') // Vue2.0 import Vue from 'vue' new Vue({ router, store, render: h => h(App) }).$mount('#app')
1.1 其他的区别
全局
// vue2 import Vue from 'vue' Vue.component(...) // vue3 import {createApp} from 'vue' let app = createApp(App) app.component(...)
filter 没有了
全局
Vue.component -> app.component
filter没了 filter -> computed/method
v-model value+input -> value+input || modelValue+update:modelValue
函数h render(h) -> import {h} from ‘vue’
data data: {} || data(){} -> data(){}
异步组件 ()=>import(’…’) -> defineAsyncComponent(()=>import(’…’))
事件 e m i t 、 emit、 emit、on、… -> $emit
其他 …
2. 响应式数据
模板定制
<template> <div class="hello" style="border:1px solid"> <h1 ref="root">{{ msg }}</h1> {{state.count}} double is {{double}} <button @click="add">+</button> </div> </template>
2.1 声明响应式数据
// Vue2 export default { // .... data() { return { state: { count: 0 } }; }, } // Vue3 reactive export default { // .... setup(){ const state = reactive({ count:0 }) return {state} } }
2.2 自定义事件
// Vue2 export default { // .... methods: { add() { this.state.count++; } }, } // Vue3 export default { // .... setup(){ const add = () => { state.count++ } return {add} } }
2.3 计算属性
// Vue2 export default { // ... computed: { double() { return this.state.count * 2; } }, } // Vue3 export default { // ... setup(){ const double = computed (() => state.count * 2 ) return {double} } }
2.4 监听器
// Vue2 export default { // ... watch: { count: value => { console.log("count is changed:", value); } } } // Vue3 export default { // ... setup(){ watch( () => state.count, value => { console.log('state change :',value) } ) } }
2.5 生命周期及其获取Dom元素
// Vue2 <div ref="dom"></div> export default { // ... mounted() { this.$refs.dom.style.color = "red"; } } // Vue3 <h1 ref="myRef">7777777777777777777</h1> export default { // ... setup() { // ref 创建一个响应式的数据对象 const myRef = ref(null); onMounted(() => { console.dir(myRef); const dom = myRef.value dom.style.color = 'red' }); return { myRef } }, }
3. API 列表
const { createApp, reactive, // 创建响应式数据对象 ref, // 创建一个响应式的数据对象 toRefs, // 将响应式数据对象转换为单一响应式对象 isRef, // 判断某值是否是引用类型 computed, // 创建计算属性 watch, // 创建watch监听 // 生命周期钩子 onMounted, onUpdated, onUnmounted, } = Vue
3.1 setup使用composition API的入口
setup函数会在 beforeCreate之后 created之前执行
setup(props,context){ console.log('setup....',) console.log('props',props) // 组件参数 console.log('context',context) // 上下文对象 }
3.2 reactive
reactive() 函数接受一个普通对象 返回一个响应式数据对象
const state = reactive({ count: 0, plusOne: computed(() => state.count + 1) })
3.3 ref 与 isRef
ref 将给定的值(确切的说是基本数据类型 ini 或 string)创建一个响应式的数据对象
isRef 其实就是判断一下是不是ref生成的响应式数据对象
// 定义创建响应式数据 const time = ref(new Date()) // 设置定时器为了测试数据响应 setInterval(() => time.value = new Date(), 1000) // 判断某值是否是响应式类型 console.log('time is ref:', isRef(time)) console.log('time', time) console.log('time.value', time.value) // 我们看看模板里面我们这样展示 template: ` <div> <div>Date is {{ time }}</div> </div> `
3.4 toRefs
toRefs就是ref的批量操作
toRefs 可以将reactive创建出的对象展开为基础类型
1.
// 如果不用toRefs const state = reactive({ count: 0, plusOne: computed(() => state.count + 1) }) return { state } // 模板渲染要这样写 template: ` <div> <div>count is {{ state.count }} </div> <div>plusOne is {{ state.plusOne }}</div> </div> ` // 我们再看看用了toRefs const state = reactive({ count: 0, plusOne: computed(() => state.count + 1) }) return { ...toRefs(state) } // 模板渲染要这样写 template: ` <div> <div>count is {{ count }} </div> <div>plusOne is {{ plusOne }}</div> </div> `
3.5 watch 定义监听器
这个其实没有什么新东西,需要手动指定
watch(() => 谁,()=>{}) watch(() =>[a,b....], ()=>{}) watch(() => state.count * 2, val => { console.log(`count * 2 is ${val}`) })
3.5.1 watchEffect 自动监听
自动监听,当watchEffect内部使用了某个值会自动监听这个值变化,当这个值变化的时候触发
watchEffect((invalidate) => { console.log('a变了',a) }) invalidate: 参数是一个函数,放监听器失效的时候触发。监听器什么时候会失效?stop的时候、或者组件销毁 invalidate(()=>{})
3.5.2 停止监听
let stop = watchEffect((invalidate) => {}) let stop1 = watch(() => 谁,()=>{}) stop() stop1()
3.6 ffect 副作用函数
响应式对象修改会触发这个函数
// 副作用函数 effect(() => { console.log('数值被修改了..',state.count) })
3.7 computed 计算属性
const state = reactive({ count: 0, plusOne: computed(() => state.count + 1) })
3.8 provide/inject 依赖注入
// 外部组件 setup(){ provide(名字,值【可以是任何类型】) } // 内部 setup(){ const a = inject(名字,可选参:默认值)
toRaw 与 markRaw
toRaw 拿出reactive、ref、readonly这个方法转换前的原始互数据,对原始数据操作不会被监听
markRaw 保持一个数据永远是原始数据不会被监听
unRef 、toRef、customRef
unRef :获取ref对象的原始数据,那为什么不用toRaw
toRaw连着value一起拿,获取出来就是 => {value:xxx}
unRef是ref专用 => xxx
toRef: 也是把一个数据转成ref对象,但是的ref专有一些区别
let json = {a:12} const b = ref(json.a) b.value++ console.log(json,b) // {a:12} // {value:13} const a = toRef(json,'a') a.value++ console.log(json,a) // {a:13} // {value:13}
ref toRef
相当于把原始数据拷贝,以后操作与原始数据无关 依然存在引用关系
改ref对象后模板会重新渲染 不会触发模板渲染
customRef:自定义ref
function myCustomRef(){ let _val = 12 return customRef((track,trigger)=>{ return { get(){ track() return _val }, set(newVal){ _val = newVal // 通知vue,请重新渲染 trigger() } } }) }
setup(){ const arr = myAjax('xxxx',[]) return { arr } } function myAjax(url,initval){ let _data = initval return customRef((track,trigger)=>{ axios(url).then(res=>{ _data = res._data trigger() }) return { get(){ track() return _data }, set(newVal){ _data = newVal // 通知vue,请重新渲染 trigger() } } }) }
Vue2 | Vue3
--------------------------------------------------
beforeCreate | setup(替代)
created | setup(替代)
beforeMount | onBeforeMount
mounted | onMounted
beforeUpdate | onBeforeUpdate
updated | onUpdated
beforeDestroy | onBeforeUnmount
destroyed | onUnmounted
errorCaptured | onErrorCaptured
4. Teleport 组件
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML
// vue3 新添加了一个默认的组件就叫 Teleport,我们可以拿过来直接使用,它上面有一个 to 的属性,它接受一个css query selector 作为参数,这就是代表要把这个组件渲染到哪个 dom 元素中 <teleport to="#modal"> <div id="center"> <h1>this is a modal</h1> </div> </teleport>
4.1 Suspense - 异步组件好帮手
定义一个异步组件,在 setup 返回一个 Promise,AsyncShow.vue
<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>
使用 async await 改造一下异步请求, 新建一个 DogShow.vue 组件
<template> <img :src="result && result.message"> </template> <script lang="ts"> import axios from 'axios' import { defineComponent } from 'vue' export default defineComponent({ async setup() { const rawData = await axios.get('https://dog.ceo/api/breeds/image') return { result: rawData.data } } }) </script>
<Suspense> <template #default> <async-show /> <dog-show /> </template> <template #fallback> <h1>Loading !...</h1> </template> </Suspense>
5. 路由Vue-router
5.1 创建路由
// Vue2 const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes: [ // 路由配置不变 ] }) // Vue3 const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes: [ // 路由配置不变 ] })
5.2 使用路由
// Vue2 export default { name: "Home", methods: { goHome() { this.$router.push('Home') } } }; // Vue3 export default { setup() { const router = useRouter() const goHome = () => router.push('Home') return { goHome}; } };
6.0 统一状态管理Vuex
6.1 创建Vuex
// Vue2 export default new Vuex.Store({ state: { count:1 }, mutations: { inc(state){ state.count ++ } }, actions: { }, modules: { } }) // Vue3 export default Vuex.createStore({ state: { count:1 }, mutations: { add(state){ state.count ++ } }, actions: { }, modules: { } });
6.2 使用Vuex
// Vue2 export default { name: "Home", data() { return { state: this.$store.state }; }, computed: { double() { return this.$store.state.count * 2; }, }, methods: { add() { this.$store.commit("add"); } } }; // Vue3 import { computed, reactive } from "vue"; import { useStore } from "vuex"; export default { setup() { const store = useStore() const state = store.state const double = computed(() => store.state.count * 2) const add = () => { store.commit("add"); }; return { state, add ,double}; } };