vue3-Compostion API学习笔记

371 阅读3分钟

创建vue3项目

npm init vite-app 项目名称
  1. setup函数

    • 是组合api的起点 是个函数
    • 在beforeCreate前执行,组件创建前,这里访问不到组件实例
    • setup函数中没有this
    • 提供模版中的数据和函数,需要在setup中返回
 <script>
     export default {
         setup(){
             const msg = 'hello vue3'
         }
         return { msg }
     }
 </script>

2.组件生命周期函数

  • 和vue2.x版本使用基本差不多 我们在使用的时候需要从vue中引入
 import { onBeforeMount,onMounted } from 'vue'
 export default {
     // DOM渲染前的钩子
     onBeforeMount(()=>{
         console.log('DOM渲染前的钩子',document.getElementsByClassName('main'))
     })
 ​
     //DOM渲染后的钩子函数
     onMounted(()=>{
         console.log('DOM渲染后的钩子',document.getElementsByClassName('main'))
     })
 }

3.reactive函数 定义复杂数据类型的响应式数据

 <div>
     <h1>{{data.name}}</h1>
     <button @click='change'>修改名字</button>
 </div>      
 ​
 import { reactive } from 'vue'
 ​
 setup(){
     // 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
     const data = reactive({
         name: 'ls',
         age: 18
     })
     const change = ()=>{
         data.name = 'zs'
     }
     
     return { data, change }
 }

4.toRef是函数,是可以将响应式数据中的某个属性转化为单独的响应式数据,并且值是关联的

 <div>
     <h1>{{name}}</h1>
     <button @click='change'>修改名字</button>
 </div>      
 ​
 import { reactive, toRef } from 'vue'
 ​
 setup(){
     // 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
     const data = reactive({
         name: 'ls',
         age: 18
     })
     // toRef的参数 第一个是需要修改属性值的对象本身,第二个是需修改的属性名 是字符串
     const name = toRef(data,'name')
     const change = ()=>{
         name.value = 'zs'
     }
     
     return { name, change }
 }
 // 使用场景:在我们已经有了响应式数据之后,但是模版中只需要其中一个数据。

5.toRefs是函数,将响应式对象中的所有属性转换为单独响应式数据,对象成为普通对象,并且值是关联的

 <div>
     <h1>{{name}}</h1>
     <h1>{{age}}</h1>
     <button @click='change'>修改名字</button>
 </div>      
 ​
 import { reactive, toRefs } from 'vue'
 ​
 setup(){
     // 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
     const data = reactive({
         name: 'ls',
         age: 18
     })
 ​
     const person = toRefs(data)
     // 在定义方法修改数据的时候 我们也可以解构出来 注意 这里不能解构data,会报错
     const change = ()=>{
         // 第一种写法
         person.name.value = 'zs'
         // 第二种 可以直接使用data中数据修改也是可以的,都是响应式数据
         data.name = 'zs'
     }
     // 使用展开运算符,就可以在模版中直接使用属性名渲染数据
     return { ...data, change }
 }

6.ref函数用于定义响应式数据,一般用于简单数据类型(在修改数据的时候和toRef一直 需要 .value

 import { ref } from 'vue'
 /*
	ref也可以定义复杂数据类型的数据 在不清楚数据类型的时候我们可以这样写
	const data = ref(null)
*/  
 setup(){
     const name = ref('ls')
     const age = ref(10)
     // 修改同理
 }

7.computed函数定义计算属性,计算属性不可修改

 <template>
     <div class="main">
         <h1>今年:{{age}}岁</h1>
         <h1>后年:{{newAge}}岁</h1>
     </div>
 </template>
 ​
 <script>
 import { ref, computed } from 'vue'
 export default {
     name: 'App',
     setup(){
         //1.计算属性:当需要依赖现有的响应式数据,得到一个新的数据
         const age = ref(18)
         const newAge = computed(()=>{
             // 该函数的返回值就是计算属性的值
             return age.value + 2
         })
         return { age, newAge }
     }
 }
 </script>

8.修改计算属性computed的值,尽量不要这样去修改数据!

 <template>
     <div class="main">
         <h1>今年:{{age}}岁</h1>
         <h1>后年:{{newAge}}岁</h1>
         <input v-model='newAge'></input>    
     </div>
 </template>
 ​
 <script>
 import { ref } from 'vue'
 export default {
     name: 'App',
     setup(){
         //1.计算属性:当需要依赖现有的响应式数据,得到一个新的数据
         const age = ref(18)
         // computed 传入一个对象
         const newAge = computed({
             // get函数获取要修改的值
             get(){
                 return age.value + 2
             }
             // set 当计算属性的值被修改是触发
             set(value){
                 age.value= value - 2
             }
         })
         
         return { age, newAge }
     }
 }
 </script>

9.watch监听器

 <template>
     <div class="main">
         <h1>{{count}}</h1>
         <button @click="increment">+1</button>
     </div>
 </template>
 ​
 <script>
 import { ref, watch } from 'vue'
 export default {
     name: 'App',
     setup(){
         const count = ref(0)
         const increment = ()=>{
             count.value ++
         }
         // 监听ref数据 reactive同理,也可以监听多个数据的改变 watch([count,person],()=>{ })
         watch(count,(newVal,oldVal)=>{
             console.log(newVal,oldVal)
         },{
             // 深度监听
             deep:true
         })
         return { count, increment }
     }
 }
 // 如果要监听对象中的某一项属性值的变化
 //   watch(()=>obj.name,()=>{})
 </script>

10.ref属性,获取组件实例,vue3.0区别vue2.x的写法

 <template>
     <div class="main">
         <div ref="box">div</div>
         <ul>
             <li v-for="i in 4" key="i" :ref="liRefs">第{{i}}个li</li>
         </ul>
     </div>
 </template>
 ​
 <script>
 import { ref, onMounted } from 'vue'
 export default {
     name: 'App',
     setup(){
         // 单个数据的ref属性使用
         const box = ref(null)
         onMounted(()=>{
             console.log(box.value)
         })
         /**
          *  v-for 遍历的ref使用
          *  先定一个空的数组,用来收集遍历后的dom
          *  定义一个函数,往空数组push dom
          */
         const list = []
         const liRefs = (el)=>{
             list.push(el)
         }
         // 组件挂在完成
         /*
             这样操作存在一个问题,就是说当我页面别的数据更新变化的时候,list数组会一直push数据
             不是我们之前显示的四条数据
             我们可以在onBeforeUpdate钩子中重置list数组为空就可以解决了。
         */
         onMounted(()=>{
             console.log(list[0])
         })
         return { box, liRefs }
     }
 }
 </script>

11.组件传值 父–>子,整体写法和vue2.x无区别,也是通过绑定自定义属性

 <template>
     <div class="main">
         <h1>父组件</h1>
         <Child :count="count"/>
     </div>
 </template>
 ​
 <script>
 import Child from './child.vue'
 import { ref } from "vue";
 export default {
     name: 'App',
     components:{
       Child
     },
     setup(){
         const count = ref(100)
         return { count }
     }
 }
 </script>
 <template>
     <div class="main">
         <h1>子组件</h1>
         <span>{{count}}</span>
     </div>
 </template>
 ​
 <script>
 export default {
     name: "child",
     props:{
         count:{
             type:Number,
             default:0
         }
     },
     // 我们也在setup函数中拿到props
     setup(props){
         // 在页面加载完成之前拿到父组件传来的值
         console.log(props.count)
     }
 }
 </script>

12.子—–>父传值,和vue2.x版本一样 定义自定义函数。

 <template>
     <div class="main">
         <h1>父组件</h1>
         <hr>
         <Child :count="count" @decrement="handleDecrement"/>
     </div>
 </template>
 ​
 <script>
 import Child from './child.vue'
 import { ref } from "vue";
 export default {
     name: 'App',
     components:{
       Child
     },
     setup(){
         const count = ref(100)
         const handleDecrement = (val) => {
             count.value = val
         }
         return { count,handleDecrement }
     }
 }
 </script>
 ​
 <template>
     <div class="main">
         <h1>子组件</h1>
         <h1>{{count}}</h1>
         <button @click="decrement">子组件方法</button>
     </div>
 </template>
 ​
 <script>
 export default {
     name: "child",
     // props:['count']
     props:{
         count:{
             type:Number,
             default:0
         }
     },
     setup(props,context){
         console.log(props.count)
         // setup函数中没有this,我们不能用this.$emit触发事件
         // props接收父组件的值,contex包含了$emit的方法 或者可以解构context {emit}函数 触发事件
         const decrement = () => {
             context.emit('decrement',50)
         }
         return { decrement }
     }
 ​
 }
 </script>

13.区别于vue2.x版本的.sync双向数据绑定,vue3.0写法v-model

 <template>
     <div class="main">
         <h1>父组件</h1>
         <hr>
 <!--        <Child :count="count" @update:count="handleDecrement"/>-->
         <Child v-model:count="count"/>
     </div>
 </template>
 ​
 <script>
 import Child from './child.vue'
 import { ref } from "vue";
 export default {
     name: 'App',
     components:{
       Child
     },
     setup(){
         const count = ref(100)
         const handleDecrement = (val) => {
             console.log(111)
             count.value = val
         }
         return { count,handleDecrement }
     }
 }
 </script>
 <template>
     <div class="main">
         <h1>子组件</h1>
         <h1>{{count}}</h1>
         <button @click="decrement">子组件方法</button>
     </div>
 </template>
 ​
 <script>
 export default {
     name: "child",
     // props:['count']
     props:{
         count:{
             type:Number,
             default:0
         }
     },
     setup(props,context){
         console.log(props.count)
         // props接收父组件的值,contex包含了$emit的方法 或者可以解构context {emit}函数 触发事件
         const decrement = () => {
             context.emit('update:count',50)
         }
         return { decrement }
     }
 ​
 }
 </script>

14.provide函数和inject函数

 <template>
     <div class="main">
         <h1>父组件{{count}}</h1>
         <hr>
         <Child :count="count"/>
     </div>
 </template>
 ​
 <script>
 import Child from './child.vue'
 import { provide, ref } from "vue";
 export default {
     name: 'App',
     components:{
       Child
     },
     setup(){
         const count = ref(100)
         // 将数据传递给后代组件使用
         provide('count',count)
         return { count }
     }
 }
 </script>
 <template>
     <div class="main">
         <h2>子组件{{count}}</h2>
     </div>
 </template>
 ​
 <script>
 import { inject } from "vue";
 ​
 export default {
     name: "child",
     setup(){
         // 不能直接修改父组件传来的值,遵循单向数据流
         const count = inject('count')
 ​
         return { count }
     }
 ​
 }
 </script>

如果要修改父组件的值,需要在父组件中提供方法(provide),子组件中注入方法(inject)

 <template>
     <div class="main">
         <h1>父组件{{count}}</h1>
         <hr>
         <Child :count="count"/>
     </div>
 </template>
 ​
 <script>
 import Child from './child.vue'
 import { provide, ref } from "vue";
 export default {
     name: 'App',
     components:{
       Child
     },
     setup(){
         const count = ref(100)
         // 接收子组件的传来的数据
         const decrement = (val)=>{
             count.value -= val
         }
         // 将数据传递给后代组件使用
         provide('count',count)
         provide('decrement',decrement)
         return { count, decrement }
     }
 }
 </script>
 <template>
     <div class="main">
         <h2>子组件{{count}}</h2>
         <button @click="fn">减1</button>
     </div>
 </template>
 ​
 <script>
 import { inject } from "vue";
 ​
 export default {
     name: "child",
     setup(){
         const count = inject('count')
         const decrement = inject('decrement')
         const fn = ()=>{
             // 通知父组件每次要自减1
             decrement(1)
         }
         return { count,fn }
     }
 ​
 }
 </script>