> 文章列表 > vue3 基础

vue3 基础

vue3 基础

vue3新特性

  • 更快的渲染:Vue 3使用了新的响应式系统,将Proxy作为其核心,以取代Vue 2.x中使用的Object.defineProperty。这样可以更快地追踪变化并更新视图。
  • 更小的包体积:Vue 3改进了其打包工具,可以生成更小、更高效的代码。同时,移除了一些不常用的API,减少了库的大小。
  • 更好的Tree-Shaking支持:Vue 3通过使用ES模块来实现更好的Tree-Shaking支持,从而减小了最终打包文件的大小。
// 只导入用到的,不用的不打包进去,减少包的大小
import { xx } from 'vue'
  • 静态提升:Vue 3采用了基于编译时的静态提升技术,将组件模板编译为渲染函数,并通过hoist静态节点,以减少不必要的重复渲染和创建。
  • 更好的TypeScript支持:Vue 3使用TypeScript重新编写了核心代码,提供了更好的类型支持和开发体验。
  • 更好的代码结构和组织:Vue 3重构了其内部代码结构,以更好地组织和管理代码。

这些改进和优化使Vue 3比Vue 2.x更快、更小、更易于开发和维护

var data = {  name:'修改前的数据' }
// VUE 框架需要知道属性的改变 + 订阅发布模式 => 属性变更 更新对应DOM
// Vue2
Object.defineProperty(data,'name'{get(){console.log('获得数据');return '测试'}set(newValue){console.log('设置数据')}
})
// 设置
data.name = '修改后的数据'
// 获取
console.log(data.name)
// 新增属性
data.abc = '123' // 没有触发
Vue.set(data , 'abv','123') this.$set
// 删除属性
delete data.abc
// 数组,key是数字,不能呗框架查询,push splice也无法察觉
// vue2是重写了数组8个方法,slice pop unshift shift等,让框架知道数据改变了
// 性能也比proxy低
// vue3
let p = new Proxy(data,{set(target,proxyKey,value){console.log('增加和修改',target,proxyKey,receiver)},get(target,proxyKey,receiver){console.log('获取',target,proxyKey,receiver)},deleteProperty(target,proxyKey,receiver){console.log('删除',target,proxyKey,receiver)}
})
//代理:装饰目标,最终操作代理
// 增加
p.abc = 'xxx'
// 修改
p.abc = 'yyy'
// 获取
console.log(p.abc)
// 删除
delete p.abc
// vue3let p = new Proxy(data,{set(target,proxyKey,value){console.log('增加和修改',target,proxyKey,value);return Reflect.set();},get(target,proxyKey,value){console.log('获取',target,proxyKey,value)},deleteProperty(target,proxyKey,value){console.log('删除',target,proxyKey,value)}
})
//代理:装饰目标,最终操作代理
// 增加
p.abc = 'xxx'
// 修改
p.abc = 'yyy'
// 获取
console.log(p.abc)
// 删除
delete p.abc

 VUE3 新增13种拦截方法

  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

VUE3项目的创建

npm install -g @vue/cli// 查看版本,要求vue-cli版本在4.5以上,可以创建vue3项目
vue -Vvue create 项目名称

根据自己需求,简单配置

启动项目

进入目录下: yarn serve / npm run serve

 

 关于 vue.config.js 配置

Vue vue.config.js 的详解与配置_蓝胖子的多啦A梦的博客-CSDN博客

createApp

在Vue 3中,改变全局Vue行为的API现在被移动到了由新的createApp方法所创建的应用实例上。vue 3. 0中使用createApp来创建vue实例

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'// const app = createApp(App) ; app.use(router); app.mount('#app');
// 合并之后
createApp(App).use(router).mount('#app')

setup函数

setup函数是vue 3中专门为组件提供的新属性。

创建组件实例,然后初始化props,紧接着就调用setup函数,会在beforeCreate钩子之前被调用。

模板中使用:如果setup返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文。

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import { defineComponent } from 'vue';
export default defineComponent({name: 'Home',components: {HelloWorld},setup(props,context){console.log(context); // 类似VUE2版本中组件内的thisreturn {num:999}}
})
</script>

 

注意:在setup()函数中无法访问到this,但可以使用context

reactive函数

reactive()函数接收一个普通对象,返回一个响应式的数据对象

ref的使用

ref函数用来根据给定的基本数据类型创建一个响应式的数据对象,ref()函数调用的返回值是一个对象,这个对象上只包含一个value属性

function ref<T>(value: T):Ref<UnwrapRef<T>> 
interface Ref<T>
{value:T
}

reactive的用法与ref的用法相似,也是将数据变成响应式数据,当数据发生变化时UI也会自动更新。不同的是ref用于基本数据类型,而reactive是用于复杂数据类型 

// ref 与 reactive 的比较
<template><div class="home">{{ data.name }}{{ num }}</div>
</template><script>
import { defineComponent, reactive, ref } from 'vue';
export default defineComponent({name: 'Home',setup(props) {//基本数据类型响应式let num = ref(100);// 引用数据类型响应式 new Proxy(对象,{set(target,propKey){}})const data = reactive({name: '小太阳'})return {data,num}}
})
</script>

toRefs

【解构部分属性专用】的使用

将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的ref。每个单独的ref都是使用toRef()创建的。

<template><div class="home">{{ name }}</div>
</template><script>
import { defineComponent, reactive, ref ,toRefs} from 'vue';
export default defineComponent({name: 'Home',setup(props) {const dataRef = reactive({name: '小太阳Ref'})// 取出属性,并且响应式const { name } = toRefs(dataRef);return {name}}
})
</script>

computed计算属性 

// 只读
function computed<T>(getter:() => T,debuggerOptions?:debuggerOptions
):Readonly<Ref<Readonly<T>>>
// 可写的
function computed<T>(options:{get:() =>Tset:(value:T) => void},debuggerOptions?:DebuggerOptions
):Ref<T>

简单语法: 

<template><div class="home">{{ all }}</div>
</template><script>
import { defineComponent, reactive, computed} from 'vue';
export default defineComponent({name: 'Home',setup(props) {let state = reactive({id:10})let all = computed(()=>{return state.id+1;})return {all,}}
})</script>

watch的使用

watch()函数用来监视某些数据项的变化,从而触发某些特定的操作

// 侦听多个来源
function watch<T>(sources: WatchSource<T>[],callback: WatchCallback<T[]>,options?: WatchOptions
): StopHandle// 侦听单个来源
function watch<T>(source: WatchSource<T>,callback: WatchCallback<T>,options?: WatchOptions
): StopHandletype WatchCallback<T> = (value: T,oldValue: T,onCleanup: (cleanupFn: () => void) => void
) => voidtype WatchSource<T> =| Ref<T> // ref| (() => T) // getter| T extends object? T: never // 响应式对象interface WatchOptions extends WatchEffectOptions {immediate?: boolean // 默认:false  在侦听器创建时立即触发回调。第一次调用时旧值undefineddeep?: boolean // 默认:false       如果源是对象,强制深度遍历,以便在深层级变更时触发回调flush?: 'pre' | 'post' | 'sync' // 默认:'pre'  调整回调函数的刷新时机// pre:组件渲染前// post:侦听器延迟到组件渲染后// sync:响应依赖改变时触发onTrack?: (event: DebuggerEvent) => void   // 调试侦听器的依赖onTrigger?: (event: DebuggerEvent) => void
}

简单语法

const count = ref(0)
watch(count, (count, prevCount) =>{/* . . . */
})

举个例子:奇偶数判断

<template><div class="home">{{ id +'-'+type }}<button @click="change()">click</button></div>
</template><script>
import { defineComponent, reactive, toRefs, watch } from 'vue';
export default defineComponent({name: 'Home',setup(props) {let state = reactive({id: 10,type:'偶数'})let stop = watch(()=>state.id,(cur,old) => {if(cur % 2 == 0){state.type = '偶数'}else{state.type = '奇数'}})function change(){state.id +=1;}return {...toRefs(state),change}}
})</script>

provide和inject

父组件把值传给所有子组件,谁用谁拿

import { provide,inject } from 'vue';
//父组件
const state =  reactive({ k: 1 })
const numState  =  ref(0);
provide('k1' , state);
// 整个state传递
provide('k1' , numState);//子组件
let val = inject('k1');
let numState = inject('k2');
console.log(numState.value)

获取slots\\attrs\\emit

  • useAttrs 方法 获取 attrs 属性
  • useSlots 方法获取 slots 插槽
  • defineEmits 方法获取 emit自定义事件
import { useSlots,useAttrs } from 'vue'const { attrs, slots, emit } = context// attrs 获取组件传递过来的属性值,// slots 组件内的插槽// emit 自定义事件 子组件const slots = useSlots()
// 插槽
const attrs = useAttrs()
// 非props属性const emits = defineEmits(['getChild']);

生命周期

新版的生命周期函数,可以按需导入到组件中,且只能在setup()函数中使用

import { defineComponent, onMounted, onUnmounted, onUpdated } from 'vue';export default defineComponent({setup(props) {onMounted(() => {console.log('mounted!')})onUpdated(() => {console.log('updated!')})onUnmounted(() => {console.log('unmounted!')})return },
})

vue2/vue3

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

美女主播网