美文网首页Vue
03.vue3-组合API(下篇)

03.vue3-组合API(下篇)

作者: 东邪_黄药师 | 来源:发表于2021-12-15 22:28 被阅读0次

    组合API-computed函数

    定义计算属性:

    • 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
        })
    
        return {age, newAge}
      }
    }
    </script>
    

    高级用法:

    <template>
      <div>
        <div>今年年龄:{{ age }}</div>
        <div>后年年龄:{{ newAge }}</div>
      </div>
    </template>
    <script>
    import { computed, ref } from "vue";
    export default {
      setup() {
        const age = ref(22);
        const newAge = computed({
          get() {
            return age.value + 2;
          }, 
          set (value) {
             age.value = value - 2
          }
        })
        return { age, newAge };
      },
    }
    </script>
    

    目的:让计算属性支持双向数据绑定。

    • 总结:计算属性两种用法
    • 给computed传入函数,返回值就是计算属性的值
    • 给computed传入对象,get获取计算属性的值,set监听计算属性改变。

    组合API-watch函数

    • watch函数,是用来定义侦听器的
    • 1.监听ref定义的响应式数据
    <template>
      <div>
        <div>{{ count }}</div>
        <button @click="add">自加一</button>
        <hr />
      </div>
    </template>
    
    <script>
    import { ref, watch } from "vue";
    export default {
      setup() {
        const count = ref(16);
        const add = () => {
          count.value++;
        }
         // 当你需要监听数据的变化就可以使用watch
        // 1. 监听一个ref数据
        // 1.1 第一个参数  需要监听的目标
        // 1.2 第二个参数  改变后触发的函数
        watch(count, (newVal, oldVal) => {
          console.log(newVal, oldVal)
        })
        return { count, add }
      },
    }
    </script>
    
    • 2.监听reactive定义的响应式数据
    <template>
      <div>
        <p>{{ obj.name }}</p>
        <p>{{ obj.age }}</p>
        <p>{{ obj.brand.name }}</p>
        <button @click="updateName">改名字</button>
      </div>
    </template>
    
    <script>
    import { watch, reactive } from "vue";
    export default {
      setup() {
        const obj = reactive({
          name: "ls",
          age: 10,
          brand: {
            id: 1,
            name: "宝马",
          },
        })
        const updateName = () => {
          obj.name = 'zs'
        }
      watch(obj, ()=>{
          console.log('数据改变了')
        })
        return { obj, updateName };
      },
    }
    </script>
    
    • 3.监听多个响应式数据数据
    <template>
     <div>
          <p>count的值:{{count}}</p>
          <button @click="add">改数据</button>
        </div>
      <div>
        <p>{{ obj.name }}</p>
        <p>{{ obj.age }}</p>
        <p>{{ obj.brand.name }}</p>
        <button @click="updateName">改名字</button>
      </div>
    </template>
    
    <script>
    import { watch, reactive, ref } from "vue";
    export default {
      setup() {
         const count = ref(0)
        const add = () => {
          count.value++
        }
        const obj = reactive({
          name: "ls",
          age: 10,
          brand: {
            id: 1,
            name: "宝马",
          },
        })
        const updateName = () => {
          obj.name = 'zs'
        }
       // 3. 监听多个数据的变化
        watch([count, obj], ()=>{
          console.log('监听多个数据改变了')
        }) 
        return { count, add, obj, updateName };
      },
    }
    </script>
    
    • 4.监听reactive定义的响应式数据,某一个属性
      需要写成函数返回该属性的方式才能监听到
    <template>
      <div class="container">
          <p>{{obj.name}}</p>
          <p>{{obj.age}}</p>
          <p>{{obj.brand.name}}</p>
          <button @click="updateName">改名字</button>
      </div>
    </template>
    <script>
    import { reactive, ref, watch } from 'vue'
    export default {
      name: 'App',
      setup () {
       const obj = reactive({
          name: 'ls',
          age: 10,
          brand: {
            id: 1,
            name: '宝马'
          }
        })
        const updateName = () => {
          obj.name = 'zs'
        }
         // 4. 此时监听对象中某一个属性的变化 例如:obj.name 
        // 需要写成函数返回该属性的方式才能监听到
        watch(()=>obj.name,()=>{
          console.log('监听obj.name改变了')
        })
    
        return { obj, updateName }
      }
    }
    </script>
    
    • 5.默认触发或者需要深度监听的方法
    <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++
        }
        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
        })
       return {count, add, obj, updateName, updateBrandName}
      }
    }
    </script>
    

    组合API-ref属性

    获取DOM或者组件实例可以使用ref属性,写法和vue2.0需要区分开

    • 1.获取单个DOM或者组件
    <template>
      <div>
        <div ref="dom">我是box</div>
      </div>
    </template>
    
    <script>
    import { ref, onMounted } from 'vue'
    export default {
      setup() {
         //  1. 获取单个元素
        // 1.1 先定义一个空的响应式数据ref定义的
        // 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。
        const dom = ref(null);
        onMounted(() => {
          console.log(dom.value)
        })
      },
    }
    </script>
    
    • 2.获取v-for遍历的DOM或者组件
    <template>
      <ul>
          <li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li>
        </ul>
    </template>
    
    <script>
    import { onMounted } from 'vue'
    export default {
      setup() {
        // 1. 获取v-for遍历的元素
        // 1.1 定义一个空数组,接收所有的LI
        // 1.2 定义一个函数,往空数组push DOM
        const domList = []
        const setDom = (el) => {
          domList.push(el)
        }
        onMounted(()=>{
          console.log(domList)
        })
        return { setDom }
      },
    }
    </script>
    

    组合API-父子通讯

    • 1.父传子
    • 父组件(方法和vue2基本一致都是自定义属性)
    <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>
    
    • 子组件(子组件接收父组件数据使用props即可)
    <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)
      }
    }
    </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
        }
      },
      setup (props,{ emit }) {
        // 获取父组件数据money
        console.log(props.money)
        const changeMoney = () => {
           emit('sonSendFather',props.money/2)
        }
        return { changeMoney }
      }
    }
    </script>
    
    • 父组件:
    <template>
      <div class="container">
        <h1>父组件</h1>
        <p>{{ money }}</p>
        <hr />
        <Son :money="money" @sonSendFather="updataFather" />
      </div>
    </template>
    <script>
    import { ref } from "vue";
    import Son from "./Son.vue";
    export default {
      name: "App",
      components: {
        Son,
      },
      // 父组件的数据传递给子组件
      setup() {
        const money = ref(100);
        const updataFather = (e) => {
          money.value = e;
        }
        return { money, updataFather };
      },
    }
    </script>
    
    在vue2.x的时候 .sync 除去v-model实现双向数据绑定的另一种方式
    • 父传子:在setup种使用props数据 setup(props){ // props就是父组件数据 }
    • 子传父:触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
    • 在vue3.0中 v-model 和 .sync 已经合并成 v-model 指令
      <Son v-model:money="money" />
    

    组合API-依赖注入

    • 使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。
      provide函数提供数据和函数给后代组件使用
      inject函数给当前组件注入provide提供的数据和函数

      父组件:
    <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)
        console.log(money,'这是组件本身的数据' )
        const changeMoney = (saleMoney) => {
          console.log('changeMoney',saleMoney)
          money.value = money.value - saleMoney 
        }
        // 将数据提供给后代组件 provide
        provide('money', money)
        // 将函数提供给后代组件 provide
        provide('changeMoney', changeMoney)
    
        return { money }
      }
    }
    </script>
    

    子组件:

    <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')
        console.log( money, '这是父组件传过来的数据')
        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')
        console.log( money, '这是父组件传过来的数据')
        return { money }
      }
    }
    </script>
    <style scoped lang="less"></style>
    

    v-model语法糖

    • 在vue2.0中v-mode语法糖简写的代码
    <Son :value="msg" @input="msg=$event" />
    
    • 在vue3.0中v-model语法糖有所调整:
    <Son :modelValue="msg" @update:modelValue="msg=$event" />
    

    演示代码:

    父:
    <template>
      <div class="container">
        <!-- 如果你想获取自定义事件  -->
        <!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } -->
        <!-- 如果绑定的是js表达式  此时 $event代表触发自定义事件的传参 -->
        <!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
        <Son v-model="count" />
      </div>
    </template>
    <script>
    import { ref } from 'vue'
    import Son from './Son.vue'
    export default {
      name: 'App',
      components: {
        Son
      },
      setup () {
        const count = ref(10)
        return { count }
      }
    }
    </script>
    

    子:
    <template>
      <div class="container">
        <h2>子组件 {{modelValue}} <button @click="fn">改变数据</button></h2>
      </div>
    </template>
    <script>
    export default {
      name: 'Son',
      props: {
        modelValue: {
          type: Number,
          default: 0
        }
      },
      setup (props, {emit}) {
        const fn = () => {
          // 改变数据
          emit('update:modelValue', 100)
        }
        return { fn }
      }
    }
    </script>
    

    总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue
    补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx子传父 @update:xxx 在vue3.0 使用 v-model:xxx代替。

    相关文章

      网友评论

        本文标题:03.vue3-组合API(下篇)

        本文链接:https://www.haomeiwen.com/subject/bdmtfrtx.html