欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue3开发学习笔记(持续补充中...)

程序员文章站 2022-05-11 10:54:31
...

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

  1. ref 定义简单类型的响应式数据

    const name = ref('张三')
    

    另外,ref 获取元素

    vue2中 获取

    直接this.$refs.test

    vue3中 获取

    需要

     setup () {
        const test = ref(null)   // 先创建
        onMounted(() => { // 挂载之后在onMounted才能获取到
          console.log('test.value', test.value);
        })
      }
    
  2. reactive 定义复杂类型的响应式数据

    const obj = reactive({
          name: '张三',
          age: 18
        })
    
  3. toRef 转换响应式对象中某个属性为单独响应式数据

    // 定义响应式数据对象
    const obj = reactive({
          name: '张三',
          age: 18
        }) 
    // !!!从响应式数据对象中解构出的属性数据,不再是响应式数据
    //  let { name } = obj 不能直接解构,出来的是一个普通数据
    const name = toRef(obj, 'name') // 这样name 在模版中可以直接使用
    
  4. 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}
      }
    
  5. 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>
    
  6. 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>
    
  7. 父子组件之间通讯 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>
      
  8. 依赖注入 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