vue3开发学习笔记(持续补充中...)
1. setup
组合式api,在before create之前执行( 没法用this ), 属性,方法,生命周期钩子函数都写在这里面,要想在模版中使用setup中定义的属性或方法,记得要return出去
另外,在setup中使用vue的api或者一些函数时,要先引入
import { defineComponent, getCurrentInstance, ref, onMounted } from 'vue';
参数: setup( props, context ) { }
-
props 一个对象,里边有父组件向子组件传递的数据,子组件中使用props接受到的所有属性
-
context 上下文对象 setup( props, { attrs, slots, emit } )
attrs 是属性,相当于this.$attrs
slots 插槽 相当于this.$slots
emit 自定义事件 相当于this.$emit
2. 组合Api
-
ref 定义简单类型的响应式数据
const name = ref('张三')
另外,ref 获取元素
vue2中 获取
直接this.$refs.testvue3中 获取
需要setup () { const test = ref(null) // 先创建 onMounted(() => { // 挂载之后在onMounted才能获取到 console.log('test.value', test.value); }) }
-
reactive 定义复杂类型的响应式数据
const obj = reactive({ name: '张三', age: 18 })
-
toRef 转换响应式对象中某个属性为单独响应式数据
// 定义响应式数据对象 const obj = reactive({ name: '张三', age: 18 }) // !!!从响应式数据对象中解构出的属性数据,不再是响应式数据 // let { name } = obj 不能直接解构,出来的是一个普通数据 const name = toRef(obj, 'name') // 这样name 在模版中可以直接使用
-
toRefs 转换响应式对象中所有属性为单独响应式数据,对象成为普通对象
setup () { // 1. 响应式数据对象 const obj = reactive({ name: '张三', age: 10 }) console.log(obj) // 2. 解构或者展开响应式数据对象 // const {name,age} = obj // console.log(name,age) // const obj2 = {...obj} // console.log(obj2) // 以上方式导致数据就不是响应式数据了 const obj3 = toRefs(obj) console.log(obj3) const updateName = () => { // obj3.name.value = '张三' obj.name = '李四' } return {...obj3, updateName} }
-
computed 计算属性
<template> <div class="container"> <div>今年:{{age}}岁</div> <div>后年:{{newAge}}岁</div> </div> </template> <script> import { computed, ref } from 'vue' export default { name: 'App', setup () { // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。 const age = ref(16) // 得到后年的年龄 const newAge = computed(()=>{ // 该函数的返回值就是计算属性的值 return age.value + 2 }) // ------------------------------------------------------- // 另外还可以设置get,set方法 // 计算属性高级用法,传入对象 const newAge = computed({ // get函数,获取计算属性的值 get(){ return age.value + 2 }, // set函数,当你给计算属性设置值的时候触发 set (value) { age.value = value - 2 } }) return {age, newAge} } } </script>
-
watch 监听器
监听ref定义的响应式数据
监听多个响应式数据数据
监听reactive定义的响应式数据
监听reactive定义的响应式数据,某一个属性
深度监听 deep: true
默认执行 immediate: true
<template> <div class="container"> <div> <p>count的值:{{count}}</p> <button @click="add">改数据</button> </div> <hr> <div> <p>{{obj.name}}</p> <p>{{obj.age}}</p> <p>{{obj.brand.name}}</p> <button @click="updateName">改名字</button> <button @click="updateBrandName">改品牌名字</button> </div> </div> </template> <script> import { reactive, ref, watch } from 'vue' export default { name: 'App', setup () { const count = ref(0) const add = () => { count.value++ } // 当你需要监听数据的变化就可以使用watch // 1. 监听一个ref数据 // 1.1 第一个参数 需要监听的目标 // 1.2 第二个参数 改变后触发的函数 // watch(count, (newVal,oldVal)=>{ // console.log(newVal,oldVal) // }) const obj = reactive({ name: 'ls', age: 10, brand: { id: 1, name: '宝马' } }) const updateName = () => { obj.name = 'zs' } const updateBrandName = () => { obj.brand.name = '奔驰' } // 2. 监听一个reactive数据 watch(obj, ()=>{ console.log('数据改变了') }) watch(()=>obj.brand, ()=>{ console.log('brand数据改变了') },{ // 5. 需要深度监听 deep: true, // 6. 默认触发 immediate: true }) // 3. 监听多个数据的变化 // watch([count, obj], ()=>{ // console.log('监听多个数据改变了') // }) // 4. 此时监听对象中某一个属性的变化 例如:obj.name // 需要写成函数返回该属性的方式才能监听到 // watch(()=>obj.name,()=>{ // console.log('监听obj.name改变了') // }) return {count, add, obj, updateName, updateBrandName} } } </script>
-
父子组件之间通讯 props emit
父子组件之间传值,在vue2中,父传子是通过在子组件中props接受父组件中传递的值,子传父是通过this.$emit 抛出一个事件
在vue3中,大概也是这样,只是写法不同
-
父传子 在setup种使用props数据 setup(props){ // props就是父组件数据 }
<template> <div class="container"> <h1>父组件</h1> <p>{{money}}</p> <hr> <Son :money="money" /> </div> </template> <script> import { ref } from 'vue' import Son from './Son.vue' export default { name: 'App', components: { Son }, // 父组件的数据传递给子组件 setup () { const money = ref(100) return { money } } } </script>
<template> <div class="container"> <h1>子组件</h1> <p>{{money}}</p> </div> </template> <script> import { onMounted } from 'vue' export default { name: 'Son', // 子组件接收父组件数据使用props即可 props: { money: { type: Number, default: 0 } }, setup (props) { // 获取父组件数据money console.log(props.money) } } </script>
-
子传父 触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
<template> <div class="container"> <h1>父组件</h1> <p>{{money}}</p> <hr> + <Son :money="money" @change-money="updateMoney" /> </div> </template> <script> import { ref } from 'vue' import Son from './Son.vue' export default { name: 'App', components: { Son }, // 父组件的数据传递给子组件 setup () { const money = ref(100) + const updateMoney = (newMoney) => { + money.value = newMoney + } + return { money , updateMoney} } } </script>
<template> <div class="container"> <h1>子组件</h1> <p>{{money}}</p> + <button @click="changeMoney">花50元</button> </div> </template> <script> import { onMounted } from 'vue' export default { name: 'Son', // 子组件接收父组件数据使用props即可 props: { money: { type: Number, default: 0 } }, // props 父组件数据 // emit 触发自定义事件的函数 + setup (props, {emit}) { // 获取父组件数据money console.log(props.money) // 向父组件传值 + const changeMoney = () => { // 消费50元 // 通知父组件,money需要变成50 + emit('change-money', 50) + } + return {changeMoney} } } </script>
-
-
依赖注入 provide和inject
使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。
<template> <div class="container"> <h1>父组件 {{money}} <button @click="money=1000">发钱</button></h1> <hr> <Son /> </div> </template> <script> import { provide, ref } from 'vue' import Son from './Son.vue' export default { name: 'App', components: { Son }, setup () { const money = ref(100) const changeMoney = (saleMoney) => { console.log('changeMoney',saleMoney) money.value = money.value - saleMoney } // 将数据提供给后代组件 provide provide('money', money) // 将函数提供给后代组件 provide provide('changeMoney', changeMoney) return { money } } } </script> <style scoped lang="less"></style>
<template> <div class="container"> <h2>子组件 {{money}}</h2> <hr> <GrandSon /> </div> </template> <script> import { inject } from 'vue' import GrandSon from './GrandSon.vue' export default { name: 'Son', components: { GrandSon }, setup () { // 接收祖先组件提供的数据 const money = inject('money') return { money } } } </script> <style scoped lang="less"></style>
<template> <div class="container"> <h3>孙组件 {{money}} <button @click="fn">消费20</button></h3> </div> </template> <script> import { inject } from 'vue' export default { name: 'GrandSon', setup () { const money = inject('money') // 孙组件,消费50,通知父组件App.vue组件,进行修改 // 不能自己修改数据,遵循单选数据流原则,大白话:数据谁定义谁修改 const changeMoney = inject('changeMoney') const fn = () => { changeMoney(20) } return {money, fn} } } </script> <style scoped lang="less"></style>
3. inheritAttrs
官方文档,如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false
。 what ???
可以这样说,当 inheritAttrs 为false时,在渲染出的dom上,不会有写在 父组件中的 子组件标签上的 属性
如果为默认true, 在渲染出的dom上,就会有这个属性
可以参考 https://www.cnblogs.com/luyuefeng/p/11106172.html
4. getCurrentInstance
getCurrentInstance 支持访问内部组件实例
只能在setup 或生命周期钩子中调用
官网文档中给出一个warning
getCurrentInstance
只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用 getCurrentInstance
。请不要把 它当作在组合式 API 中获取 this
的替代方案来使用。
可以参考 https://my.oschina.net/u/4355717/blog/4767509
上一篇: css3背景渐变属性
下一篇: HTML5 新增的主体结构元素