vue3.0用法及改变(基础简介)
vue3.0中将采用组合式API(compositionApi) 替换了2.0的选项式API(optionsApi)
compositionApi:基于函数组合的API(把一个个功能放在一个函数内),组件内有一个setup的钩子,在这个钩子内,用到哪个功能就调用哪个函数
也就是vue2.0中,在data里创建的变量,可能会在methed 或 watch 或其他选项里用到,一旦系统出错,需要一个个地方去排查,操作不便,而组合式API 是将所有属性变量值都放在了compositionAPI 内,每种属性变量值都放在一起
// setup 实际上就是取代了2.0内的beforeCreate 和created // setup 相当于一个调度者,所有都可以写在这里面 // 基本用例:(非工程化用法)里面不再用data,metheds...等分开的属性函数,直接---> <div>{{msg}}</div> <button @click='btn'>点击</button> setup(props,context){ // 参数1props 父子传参接收 参数2context 上下文接收 return{ msg:'我是消息信息...', btn: ()=>{ console.log('我被点击了....'); } } } // setup 内不可调用this. 因为它取代的是beforeCreate 和 created,所以被挂载前调用。注意:beforeCreate 这个在3.0中没有了因为用了setup // 所以没有this. 以及setup 内不能调生命周期当中任何内容,反过来,例如methods 或其他生命周期内访问setup 内的内容是被允许的,例如: methods:{ getSetup(){ console.log(this.$options.setup(),'访问setup.....') } } // 注意:如果用了setup 就尽量不要再分开去在外面用methods 等这种选项式API(虽然它能兼容)
// ref 让基础类型的数据具备响应式 // 在setup 内创建的变量,不像之前optionsAPI 那样,可以在页面F12 控制台通过修改属性值实现页面修改,所以fef 的作用出现了,例:(非工程化用法) setup(props,context){ const {ref} = vue // 从vue 中引入 let msg = ref('我是消息信息') // 用ref包裹后就成了响应式 return{msg} } // 在optionsAPI 中实现响应式是通过代理原理,这里compositionAPI 用ref 也是通过代理的原理,通过 proxy({value:'我是消息信息'}) //因为 ref 的底层原理是proxy ,是一个对象,所以在setup 内使用修改的时候不能直接 '=' 号赋值,需要通过msg.value = '我是新的消息信息' // 在页面展示时,底层会转换,所以在template 中的html 代码中不需要.value 获取展示
// reactice (让引用类型也就是对象或数组的数据具备响应式) // 例:(非工程化基本用法) <div>{{obj.name}}</div> setup(props,context){ const { reactive} = vue // 从 vue中引入 let obj = reactive({name:'tom',age:'10'}); return{obj} } // 同理,reactive 的底层原理也是proxy proxy({name:'tom',age:'10'}) // 在setup 内使用修改的时候,直接 obj.name = '李四'
// readonly (只读,不希望被修改) // 例:(非工程化基本用法) setup(props,context){ const {readonly} = vue // 引入 let obj = readonly({name:'tom',age:'10'}) return {obj} }
// toRefs (响应式结构) // 如果用之前的const {name,age}=obj 这种方式结构不具备响应式 // 原理也是proxy 代理 proxy({name:'tom',age:'10'}) 然后解析成 name:proxy({value:'tom'}) age:proxy({value:'10'}) 由此最终成了响应式 // 例:(非工程化用法) setup(props,context){ const {reactive,toRefs} = vue // 引入 let obj = reactive({name:'tom',age:'10'}); const {name,age} = toRefs(obj) return{name,age} }
// toRef (对于可有可无的值,或者不确定是否有的值设定) // 例:(非工程化基本用法) setup(props,context){ const { reactive,toRefs,toRef} = vue // 引入 let obj = reactive({name:'tom',age:'10'}); let {name,age} = toRefs(obj) let sex = toRef(obj,'sex') // 不确定sex 值是否有,如果没有默认undefined return{name,age,sex} // 如果不用toRef 设置,直接强行在toRefs 内取值会报错 }
// setup 的参数context 上下文传递 // context有三个属性: // 1. attrs:可以拿到no-poros的值(例如样式style) // 2. slots:可通过 slots.default() 拿到插槽的元素标签及获取相应属性(是个数组) // 3. emit:使用自定义事件(子传父事件) //例:基本用法(非工程化用法) // 针对slots 参数 vue中底层有个h 函数,const {h} = vue; return ()=> h('div',{style:'color:#fff'},[slots.default()]) 这样可以动态创建一个div 插槽,绑定什么属性,放什么东西 setup(props,context){ const {attrs,slots,emit} = context } // emit 的基本用法(非工程化用法) setup(props,context){ const {emit} = context // 引入 function btnClick(){ const data = {name:'tom',age:'10'} emit('父组件方法名',data) // 替代的2.0中子组件触发父组件传参,this.$emit()方法 } return {btnClick} }
// 计算属性 computed // 例:(非工程化用法) setup(props,context){ const {ref,computed} = vue // 引入 let num1 = ref(10); let num2 = computed(() => { return num1.value * 10 }) const add = () => { num1.value+=10; } return{num1,num2,add} } // 注意:computed 本身有get 和set 两种方法,所以也可以这么写 get:() => { return num1.value *10; } set: (res) => { num1.value = res/10 }
// 侦听器 watch // 例: setup(props,context){ const {ref,watch} = vue // 引入 let data = ref('') watch(data,(currentValue,preValue) => { }) // data:侦听的属性,currentValue:之前的值,preValue:变化后的值 let data2 = ref('') // 侦听多个值的情况 watch([data,data2],([currentData,currentData2],[preData1,preData2]) => { }) return {data,data2} } // 侦听引用类型值: let obj = reactive([name:'tom',age:'10']) watch(() => obj.name,(current,pre) => { })
// watchEffect (和watch 一样都用于侦听) // 相比watch 它有以下3个特点: // 1. 没有惰性(比如一开始的时候watch是不侦听的,只有在改变了值的时候才会触发watch 侦听,这个指的就是watch 的惰性) // 2. 更加抽象(watch 更加具体,具体到侦听哪一个属性,象watchEffect 可以侦听所有的属性,在内部都可以拿到这个值的变化) // 3. 不能访问先前值(watch 里可以拿到之前的值和现在的值,watchEffect 里不能拿到之前的值) // 另外:watchEffect 也是可以配置的(例如是否要有惰性,是否要深度侦听),只不过watch 是1对1配置,watchEffect是1对多 setup(props,context){ const {watchEffect} = vue let data = ref('') let slte = ref('') watchEffect(() => { },{immediate:true}) return {data,slte} }
// provide(数据发射出去) 和 inject(接收数据) // 用于解决父组件数据,子孙组件使用接收的单项数据流问题 // 可以解决2.0版的父子,子孙,兄弟间的组件数据传输,只能获取不能修改(数据在哪就在哪修改) // 父组件 setup(){ const {ref,reactive,provide,readonly} = vue let info = ref('小明') let obj = reactive({name:'哈哈',sex:'女'}) provide('brand',info) // 发射(订阅),相当于 provide('brand',readonly(info))表示发射出的值外部只能用不能改 } // 子组件 setup(){ const {inject} = vue const bname = inject('brand','默认值') // 这里默认值的作用是,如果没有brand发射过来的时候,显示默认值 return{bname} } // 如果想要修改发射过来的值 // 父组件(发射一个方法) const changeInfo = (params)=>{ info.value = params } provide('changeInfo',changeInfo) // 子组件(调用这个方法) const changeInfo = inject('changeInfo') const changeName=() => { changeInfo('小红') } return{changeName}
// 3.0中生命周期钩子的新写法 // 新的用setup,取消了berforeCreate 和created 两个钩子,剩下的对比之前前面都加个 on //例: setup(){ const {ref,onBeforeMount} = vue let msg = ref('小明') onBeforeMount(() => { console.log(msg,'打印msg....') }) return{msg} } // 钩子onRenderTracked:每次渲染后重新收集响应式依赖 // 钩子onRenderTriggered:每次触发页面重新渲染时自动执行 // 另外,setup 有个简写方式<script setup></script> // 在这种情况下可以不用 return ,不用setup default,直接从vue 引入开始写就行(底层已经处理统一导出处理) // 相关setup(val){},也就是setup小括号里的传参值,可以通过useContext 获取(useContext 从vue 中引入使用即可)
// 获取Dom <div ref='info'>文本内容</div> <input ref='inpts' /> setup(){ cosnt {onMounted,ref} = vue let info = ref(null) let inpts = ref(null) onMounted(() => { console.log(info.value,'打印info 值,获取dom.....') console.log(inpts.value,'打印inpts 值,获取dom...') }) return{info,inpts} }