vue3 vs vue2
// vue2 和 vue3 的区别 // 1. 创建项目 // vue2 : new Vue({render: h => h(App)}).$mount() // vue3 : createApp(App).mount('#app') // 2. template 模板 // vue2 : 必须有一个根标签 // vue3 : 可以有多个根标签 // 3. 组件创建 //options 和 vue2 一样 export default defineComponent(options = {}) // 4. setup函数: 只在初始化时执行一次,是所有组合API的入口,返回值【一个对象】直接在 this 上可以使用 // 1. 在 beforeCreate 之前执行 // 2. this 不能获取到 // 3. 组合api中也拿不到 this // 4. setup 返回值的属性会和data合并,如果重名,没有lint检查的话,setup中的方法优先级高,有lint检查会报错:重复的key // 5. setup 返回值的方法会和methods合并,如果重名,没有lint检查的话,setup中的方法优先级高,有lint检查会报错:重复的key // 6. setup 不能是一个async函数 // 7. 两个参数 setup(props, context) // 1. props 父组件中传递到子组件中 props 属性定义的所有字段 // 2. context // 1. attrs: Proxy : 除了 props 接受的属性外,其他传递的属性; 类似于vue2的 $attrs // 2. emit: (event, ...args) => instance.emit(event, ...args) 类似于vue2的 $emit 子组件向父组件传参数 // 3. slots: Proxy 类似于vue2的 $slots // 4. expose: exposed => {…} 组件暴露出一些data和方法给其他组件使用,比如子组件通过 $parent 或者 $refs 获取这些方法。
不expose的话,无法获取到。因为setup 的返回值仅仅提供给 h 函数使用。 // 5. 组合API // 1. ref 和 toRef 和 customRef // 1. 针对基础类型数据,如果传入的是对象类型数据,内部通过reactive处理成了proxy对象 // 2. 可以获取DOM元素 ref<HTMLElement | null>(null) // 3. ref 是数据的拷贝,只改变自己。 toRef 是强关联,数据源和自己都改变。 // 4. customRef((track, triggle) => { // track() 追踪数据 // triggle() 更新数据 //}) <template> <div class="about"> <h1>{{ count }}</h1> <button @click="updateCount">add</button> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue' export default defineComponent({ setup() { // ref函数 返回一个 ref 对象, js 中操作数据 ref.value, 在模板中使用值不需要用 .value const count = ref(0) const updateCount = () => { count.value++ } // setup 返回一个对象 return { count, updateCount } }, }) </script> // 2. reactive 创建一个响应式数据 -- 针对对象类型数据: 返回一个proxy代理对象 reactive({ name: '法外狂徒', age: '28', cars: ['奔驰', '宝马', '路虎'], opt: { salary: 2.1 } }) // 3. 计算属性函数 computed() // 1. 返回一个 ref 对象, // 2. computed(() => {}) 只传入一个回调是 get // 3. computed({get() {}, set(val){}}) 同时有get 和 set时,传入一个对象 // 4. 监听函数 watch 和 watchEffect // 1. watch(target, ()=>{}, {deep,immediate}) 默认不立即执行 // 2. watchEffect(()=>{}) 默认会执行一次 // 3. 监听多个数据 watch([a,b,c], ()=>{}) // 4. 监听的数据不是响应式的需要用回调方式 监听多个数据 watch([()=>a,()=>b,c], ()=>{}) // 5. 生命周期的变化: 由option选项变更为组合API, vue2中的生命周期依然可用除了(beforeDestory,destoryed),vue3对应生命周期早于vue2执行 // 1. beforeCreate -> setup // 2. created -> setup // 3. beforeMount -> onBeforeMount(()=>{}) // 4. mounted -> onMounted(()=>{}) // 5. beforeUpdate -> onBeforeUpdate(()=>{}) // 6. updated -> onUpdated(()=>{}) // 7. beforeDestory -> onBeforeUnmount(()=>{}) // 8. destoryed -> onUnmounted(()=>{}) // 6. 自定义 hooks: 一个函数 // hooks 封装 axios 请求 import { ref } from "vue" import axios from 'axios' export default function<T> (url: string) { const errMsg = ref('') const loading = ref(true) const data = ref<T|null>(null) const status = ref(200) axios.get(url).then(res => { loading.value = false data.value = res.data status.value = res.status }).catch((err) => { loading.value = false errMsg.value = err }) return { status, errMsg, data, loading } } // 7. toRefs: 响应式对象变为展开为单个响应式数据, 每个属性都是 ref 对象; // 1. state = {name: 'aa', age: '111'} ...state 展开后不是响应式对象; ...toRefs(state) 展开后每个属性都是ref对象 // 8. shallowRef 和 shallowReactive: 浅响应式。 // 9. readonly 和 shallowReadonly // readyonly(reactive(state)) 深度只读(不能修改) // shallowReadonly(reactive(state)) 浅只读(reactive处理的数据只能修改一层结构)。 // 10. toRow 和 markRow // 1. toRow 响应式数据变为普通数据,可逆 // 2. markRow 响应式数据变为普通数据,不可逆 // 11. 判断响应式数据方法 // 1. isReadonly 判断是否是 readonly 方式创建的响应式数据 // 2. isReactive 判断是否是 reactive 方式创建的响应式数据 // 3. isRef 判断是否是 ref 方式创建的响应式数据 // 4. isProxy 判断是否是 reactive 和 readonly 方式创建的响应式数据 // 12. 手写组合API // 6. 响应式原理变化 // vue2:Object.defineProperty Object.defineProperty(vm, 'name', { get: function () { return this[sourceKey][key] }, set: function (val) { this[sourceKey][key] = val } }) // vue3 数据劫持原理 Proxy + Reflect const user = { name: '张三', age: 30, child: { name: '小张', age: 5 } } const proxyUser = new Proxy(user, { get(target, prop) { return Reflect.get(target, prop) }, set(target, prop, val) { return Reflect.set(target, prop, val) }, deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) // 7. 虚拟DOM重写
// vue2 和 vue3 的区别
// 1. 创建项目 // vue2 : new Vue({render: h => h(App)}).$mount() // vue3 : createApp(App).mount('#app') // 2. template 模板 // vue2 : 必须有一个根标签 // vue3 : 可以有多个根标签 // 3. 组件创建 //options 和 vue2 一样 export default defineComponent(options = {})
// 4. setup函数: 只在初始化时执行一次,是所有组合API的入口,返回值【一个对象】直接在 this 上可以使用// 1. 在 beforeCreate 之前执行// 2. this 不能获取到// 3. 组合api中也拿不到 this// 4. setup 返回值的属性会和data合并,如果重名,没有lint检查的话,setup中的方法优先级高,有lint检查会报错:重复的key// 5. setup 返回值的方法会和methods合并,如果重名,没有lint检查的话,setup中的方法优先级高,有lint检查会报错:重复的key// 6. setup 不能是一个async函数// 7. 两个参数 setup(props, context) // 1. props 父组件中传递到子组件中 props 属性定义的所有字段 // 2. context // 1. attrs: Proxy : 除了 props 接受的属性外,其他传递的属性; 类似于vue2的 $attrs // 2. emit: (event, ...args) => instance.emit(event, ...args) 类似于vue2的 $emit 子组件向父组件传参数 // 3. slots: Proxy 类似于vue2的 $slots // 4. expose: exposed => {…} 组件暴露出一些数据,默认暴露 props声明的和 return 返回的。定义 expose 后取代默认暴露的属性 // 5. 组合API// 1. ref 和 toRef 和 customRef// 1. 针对基础类型数据,如果传入的是对象类型数据,内部通过reactive处理成了proxy对象// 2. 可以获取DOM元素 ref<HTMLElement | null>(null)// 3. ref 是数据的拷贝,只改变自己。 toRef 是强关联,数据源和自己都改变。// 4. customRef((track, triggle) => {// track() 追踪数据// triggle() 更新数据 //})<template> <div class="about"><h1>{{ count }}</h1><button @click="updateCount">add</button> </div></template><script lang="ts">import { defineComponent, ref } from 'vue'
export default defineComponent({ setup() {// ref函数 返回一个 ref 对象, js 中操作数据 ref.value, 在模板中使用值不需要用 .valueconst count = ref(0)
const updateCount = () => { count.value++}// setup 返回一个对象return { count, updateCount} },})</script>// 2. reactive 创建一个响应式数据 -- 针对对象类型数据: 返回一个proxy代理对象reactive({name: '法外狂徒',age: '28',cars: ['奔驰', '宝马', '路虎'],opt: {salary: 2.1}})// 3. 计算属性函数 computed()// 1. 返回一个 ref 对象,// 2. computed(() => {}) 只传入一个回调是 get// 3. computed({get() {}, set(val){}}) 同时有get 和 set时,传入一个对象// 4. 监听函数 watch 和 watchEffect// 1. watch(target, ()=>{}, {deep,immediate}) 默认不立即执行// 2. watchEffect(()=>{}) 默认会执行一次// 3. 监听多个数据 watch([a,b,c], ()=>{})// 4. 监听的数据不是响应式的需要用回调方式 监听多个数据 watch([()=>a,()=>b,c], ()=>{})// 5. 生命周期的变化: 由option选项变更为组合API, vue2中的生命周期依然可用除了(beforeDestory,destoryed),vue3对应生命周期早于vue2执行// 1. beforeCreate -> setup// 2. created -> setup// 3. beforeMount -> onBeforeMount(()=>{})// 4. mounted -> onMounted(()=>{})// 5. beforeUpdate -> onBeforeUpdate(()=>{})// 6. updated -> onUpdated(()=>{})// 7. beforeDestory -> onBeforeUnmount(()=>{})// 8. destoryed -> onUnmounted(()=>{})// 6. 自定义 hooks: 一个函数// hooks 封装 axios 请求import { ref } from "vue"import axios from 'axios'export default function<T> (url: string) {const errMsg = ref('')const loading = ref(true)const data = ref<T|null>(null)const status = ref(200)
axios.get(url).then(res => {loading.value = falsedata.value = res.datastatus.value = res.status}).catch((err) => {loading.value = falseerrMsg.value = err})return {status,errMsg,data,loading}}// 7. toRefs: 响应式对象变为展开为单个响应式数据, 每个属性都是 ref 对象;// 1. state = {name: 'aa', age: '111'} ...state 展开后不是响应式对象; ...toRefs(state) 展开后每个属性都是ref对象// 8. shallowRef 和 shallowReactive: 浅响应式。// 9. readonly 和 shallowReadonly // readyonly(reactive(state)) 深度只读(不能修改)// shallowReadonly(reactive(state)) 浅只读(reactive处理的数据只能修改一层结构)。// 10. toRow 和 markRow// 1. toRow 响应式数据变为普通数据,可逆// 2. markRow 响应式数据变为普通数据,不可逆// 11. 判断响应式数据方法// 1. isReadonly 判断是否是 readonly 方式创建的响应式数据// 2. isReactive 判断是否是 reactive 方式创建的响应式数据// 3. isRef 判断是否是 ref 方式创建的响应式数据// 4. isProxy 判断是否是 reactive 和 readonly 方式创建的响应式数据// 12. 手写组合API
// 6. 响应式原理变化// vue2:Object.defineProperty Object.defineProperty(vm, 'name', { get: function () { return this[sourceKey][key] }, set: function (val) { this[sourceKey][key] = val } })
// vue3 数据劫持原理 Proxy + Reflect const user = { name: '张三', age: 30, child: { name: '小张', age: 5 } } const proxyUser = new Proxy(user, { get(target, prop) { return Reflect.get(target, prop) }, set(target, prop, val) { return Reflect.set(target, prop, val) }, deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } })
// 7. 虚拟DOM重写