Vue3-Composition-API(二)

news2024/11/28 10:55:19

一、computed函数使用

1.computed

在前面我们讲解过计算属性computed:当我们的某些属性是依赖其他状态时,我们可以使用计算属性来处理

  • 在前面的Options API中,我们是使用computed选项来完成的;

  • 在Composition API中,我们可以在 setup 函数中使用 computed 方法来编写一个计算属性;

如何使用computed呢?

  • 方式一:接收一个getter函数,并为 getter 函数返回的值,返回一个不变的 ref 对象;
  • 方式二:接收一个具有 get 和 set 的对象,返回一个可变的(可读写)ref 对象;
const fullName = computed(() => {
    return firstName.value + " " + lastName.value
})
const fullName = computed({
    get: () => {
        return firstName.value + " " + lastName.value
    },
    set: newValue => {
        const names = newValue.split(" ")
        firstName.value = names[0]
        lastName.value = names[1]
    }
})

2.setup中使用ref

在setup中如何使用ref获取元素或者组件?

  • 其实非常简单,我们只需要定义一个ref对象,绑定到元素或者组件的ref属性上即可;
<template>
  <!-- 1.获取元素 -->
  <h2 ref="titleRef">我是标题</h2>
  <button ref="btnRef">按钮</button>

  <!-- 2.获取组件实例 -->
  <show-info ref="showInfoRef"></show-info>

  <button @click="getElements">获取元素</button>
</template>

<script>
  import { ref, onMounted } from 'vue'
  import ShowInfo from './ShowInfo.vue'

  export default {
    components: {
      ShowInfo
    },
    setup() {
      const titleRef = ref()
      const btnRef = ref()
      const showInfoRef = ref()

      // mounted的生命周期函数
      onMounted(() => {
        console.log(titleRef.value)
        console.log(btnRef.value)
        console.log(showInfoRef.value)

        showInfoRef.value.showInfoFoo()
      })

      function getElements() {
        console.log(titleRef.value)
      }

      return {
        titleRef,
        btnRef,
        showInfoRef,
        getElements
      }
    }
  }
</script>

<style scoped>
</style>

二、组件的生命周期函数

1.生命周期钩子

我们前面说过 setup 可以用来替代 data 、 methods 、 computed 等等这些选项,也可以替代生命周期钩子。

那么setup中如何使用生命周期函数呢?

  • 可以使用直接导入的 onX 函数注册生命周期钩子;
<template>
  <div>AppContent</div>
</template>

<script>
  import { onMounted, onUpdated, onUnmounted } from 'vue'

  export default {
    beforeCreate() {

    },
    // created() {

    // },
    // beforeMount() {

    // },
    // mounted() {

    // },
    // beforeUpdate() {

    // },
    // updated() {

    // }
    setup() {
      // 在执行setup函数的过程中, 你需要注册别的生命周期函数
      onMounted(() => {
        console.log("onmounted")
      })
    }
  }
</script>

<style scoped>
</style>

在这里插入图片描述

三、Provide/lnject使用

1.Provide函数

事实上我们之前还学习过Provide和Inject,Composition API也可以替代之前的 Provide 和 Inject 的选项。

我们可以通过 provide来提供数据:

  • 可以通过 provide 方法来定义每个 Property;

provide可以传入两个参数:

  • name:提供的属性名称;
  • value:提供的属性值;
let counter = 100
let info = {
    name: 'www',
    age: 10
}
provide("counter", counter)
provide("info", info)

2.Inject函数

在后代组件中可以通过 inject 来注入需要的属性和对应的值:

  • 可以通过 inject 来注入需要的内容;

inject可以传入两个参数:

  • 要 inject 的 property 的 name;
  • 默认值;
const counter = inject("counter")
const info = inject("info")

3.数据的响应式

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 和 reactive。

let counter = ref(100)
let info = reactive({
    name: 'www',
    age: 10
})
provide("counter", counter)
provide("info", info)

四、watch/watchEffect

1.侦听数据的变化

在前面的Options API中,我们可以通过watch选项来侦听data或者props的数据变化,当数据变化时执行某一些操作。

在Composition API中,我们可以使用watchEffectwatch来完成响应式数据的侦听;

  • watchEffect:用于自动收集响应式数据的依赖;
  • watch:需要手动指定侦听的数据源;

2.Watch的使用

watch的API完全等同于组件watch选项的Property:

  • watch需要侦听特定的数据源,并且执行其回调函数;
  • 默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调;
const name = ref('kobe')
watch(name, (newValue, oldValue) +> {
    console.log(newValue, oldValue)
})

const changeName = () => {
    name.value = "james"
}

3.侦听多个数据源

侦听器还可以使用数组同时侦听多个源:

const name = ref('kobe')
const age = ref(10)
watch([name,age], (newValue, oldValue) +> {
    console.log(newValue, oldValue)
})

const changeName = () => {
    name.value = "james"
}

4.watch的选项

如果我们希望侦听一个深层的侦听,那么依然需要设置 deep 为true:

  • 也可以传入 immediate 立即执行;
// 1.定义数据
const message = ref("Hello World")
const info = reactive({
    name: "why",
    age: 18,
    friend: {
        name: "kobe"
    }
})

// 2.侦听数据的变化
watch(message, (newValue, oldValue) => {
    console.log(newValue, oldValue)
})
watch(info, (newValue, oldValue) => {
    console.log(newValue, oldValue)
    console.log(newValue === oldValue)
}, {
    immediate: true
})

// 3.监听reactive数据变化后, 获取普通对象
watch(() => ({ ...info }), (newValue, oldValue) => {
    console.log(newValue, oldValue)
}, {
    immediate: true,
    deep: true
})

5.watchEffect

当侦听到某些响应式数据变化时,我们希望执行某些操作,这个时候可以使用 watchEffect。

我们来看一个案例:

  • 首先,watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖;
  • 其次,只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行;
const name = ref("abc")
const age = ref(18)

watchEffect(() => {
    console.log("watchEffect执行~")
})

6.watchEffect的停止侦听

如果在发生某些情况下,我们希望停止侦听,这个时候我们可以获取watchEffect的返回值函数,调用该函数即可。

比如在上面的案例中,我们age达到20的时候就停止侦听:

<template>
  <div>
    <h2>当前计数: {{ counter }}</h2>
    <button @click="counter++">+1</button>
    <button @click="name = 'kobe'">修改name</button>
  </div>
</template>

<script>
  import { watchEffect, watch, ref } from 'vue'

  export default {
    setup() {
      const counter = ref(0)
      const name = ref("why")

      // watch(counter, (newValue, oldValue) => {})

      // 1.watchEffect传入的函数默认会直接被执行
      // 2.在执行的过程中, 会自动的收集依赖(依赖哪些响应式的数据)
      const stopWatch = watchEffect(() => {
        console.log("-------", counter.value, name.value)

        // 判断counter.value > 10
        if (counter.value >= 10) {
          stopWatch()
        }
      })

      return {
        counter,
        name
      }
    }
  }
</script>

<style scoped>
</style>

五、自定义Hook练习

1.useCounter

我们先来对之前的counter逻辑进行抽取:

import { ref, onMounted } from 'vue'

export default function useCounter() {
  const counter = ref(0)
  function increment() {
    counter.value++
  }
  function decrement() {
    counter.value--
  }
  onMounted(() => {
    setTimeout(() => {
      counter.value = 989
    }, 1000);
  })

  return {
    counter,
    increment,
    decrement
  }
}

2.useTitle

我们编写一个修改title的Hook:

import { ref, watch } from "vue";

export default function useTitle(titleValue) {
  // document.title = title

  // 定义ref的引入数据
  const title = ref(titleValue)

  // 监听title的改变
  watch(title, (newValue) => {
    document.title = newValue
  }, {
    immediate: true
  })

  // 返回ref值
  return {
    title
  }
}

3.useScrollPosition

我们来完成一个监听界面滚动位置的Hook:

import { reactive } from 'vue'

export default function useScrollPosition() {
  // 1.使用reative记录位置
  const scrollPosition = reactive({
    x: 0,
    y: 0
  })

  // 2.监听滚动
  document.addEventListener("scroll", () => {
    scrollPosition.x = window.scrollX
    scrollPosition.y = window.scrollY
  })


  return {
    scrollPosition
  }
}

4.Hook练习

App.vue

<template>
  <div>AppContent</div>
  <button @click="changeTitle">修改title</button>

  <!-- 1.计数器 -->
  <!-- <hr>
  <home></home>
  <hr>
  <about></about> -->

  <!-- 2.home和about页面的切换 -->
  <button @click="currentPage = 'home'">home</button>
  <button @click="currentPage = 'about'">about</button>

  <component :is="currentPage"></component>

  <div class="content"></div>

  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
  <br><br><br><br><br><br>
</template>

<script>
  import { ref } from 'vue'
  import Home from './views/Home.vue'
  import About from './views/About.vue'

  import useTitle from './hooks/useTitle'

  export default {
    components: {
      Home,
      About
    },
    setup() {
      const currentPage = ref("home")

      function changeTitle() {
        useTitle("app title")
      }

      return {
        changeTitle,
        currentPage
      }
    }
  }
</script>

<style scoped>
  .content {
    width: 3000px;
    height: 100px;
    background-color: orange;
  }
</style>

views/About.vue

<template>
  <h2>About计数: {{ counter }}</h2>
  <button @click="increment">+1</button>
  <button @clcik="decrement">-1</button>
</template>

<script>
  import { onActivated } from 'vue'
  import useCounter from '../hooks/useCounter'
  import useTitle from '../hooks/useTitle'

  export default {
    setup() {

      // 切换标题
      useTitle("关于")

      return {
        ...useCounter()
      }
    }
  }
</script>

<style scoped>
</style>

views/Home.vue

<template>
  <h2>Home计数: {{ counter }}</h2>
  <button @click="increment">+1</button>
  <button @click="decrement">-1</button>

  <button @click="popularClick">首页-流行</button>
  <button @click="hotClick">首页-热门</button>
  <button @click="songClick">首页-歌单</button>

  <div class="scroll">
    <h2>x: {{ scrollPosition.x }}</h2>
    <h2>y: {{ scrollPosition.y }}</h2>
  </div>
</template>

<script>
  import { onMounted, ref } from 'vue'
  import useCounter from '../hooks/useCounter'
  import useTitle from '../hooks/useTitle'
  import useScrollPosition from '../hooks/useScrollPosition'

  export default {
    setup() {
      // 1.counter逻辑
      const { counter, increment, decrement } = useCounter()

      // 2.修改标题
      const { title } = useTitle("首页")

      // 3.监听按钮的点击
      function popularClick() {
        title.value = "首页-流行"
      }
      function hotClick() {
        title.value = "首页-热门"
      }
      function songClick() {
        title.value = "首页-歌单"
      }

      // 4.获取滚动位置
      const { scrollPosition } = useScrollPosition()
      console.log(scrollPosition)

      return {
        counter,
        increment,
        decrement,
        popularClick,
        hotClick,
        songClick,
        scrollPosition
      }
    }
  }
</script>

<style scoped>
</style>

六、script setup语法糖

1.script setup语法

<script setup>是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖,当同时使用 SFC 与组合式 API 时则推荐该语法

  • 更少的样板内容,更简洁的代码;
  • 能够使用纯 Typescript 声明 prop 和抛出事件;
  • 更好的运行时性能 ;
  • 更好的 IDE 类型推断性能 ;

使用这个语法,需要将 setup attribute 添加到 <script> 代码块上:

<script setup>
    console.log(11)
</script>

里面的代码会被编译成组件 setup() 函数的内容:

  • 这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同;
  • <script setup> 中的代码会在每次组件实例被创建的时候执行。

2.顶层的绑定会被暴露给模板

当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用:

<script setup>
    const message = ref(111)
</script>
<template>
    message: {{ message }}
</template>

响应式数据需要通过ref、reactive来创建。

3.导入的组件直接使用

<script setup>范围里的值也能被直接作为自定义组件的标签名使用:

<script setup>
    import ShowInfo from './ShowInfo.vue'
</script>
<template>
    <ShowInfo></ShowInfo>
</template>

4.defineProps() 和 defineEmits()

为了在声明 props 和 emits 选项时获得完整的类型推断支持,我们可以使用 definePropsdefineEmits API,它们将自动地在 <script setup>可用

<template>
  <div>ShowInfo: {{ name }}-{{ age }}</div>
  <button @click="showInfoBtnClick">showInfoButton</button>
</template>

<script setup>

// 定义props
const props = defineProps({
  name: {
    type: String,
    default: "默认值"
  },
  age: {
    type: Number,
    default: 0
  }
})

// 绑定函数, 并且发出事件
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
  emits("infoBtnClick", "showInfo内部发生了点击")
}

// 定义foo的函数
function foo() {
  console.log("foo function")
}
defineExpose({
  foo
})

</script>

<style scoped>
</style>

5.defineExpose()

使用 <script setup> 的组件是默认关闭的:

  • 通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定;

通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的 property:

ShowInfo.vue

function foo() {
    log("foo function")
}

defineExpose({
    foo
})

App.vue

const showInfoRef = ref(null)
function callShowInfoRef() {
    showInfoRef.value.foo()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1425498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《C程序设计》上机实验报告(四)之一维数组

1.运行程序 #include <stdio.h> void main( ) { int a[5],i,j; for(i1;i<5;i) a[i]0; for(i1;i<5;i) for(j1;j<5;j) a[j]a[i]1; printf("%d %d\n",a[0],a[3]); } 要求&#xff1a; &#xff08;1&#xff09;输入并调试上述源程序&#xff0c;…

安装 vant-ui 实现底部导航栏 Tabbar

本例子使用vue3 介绍 vant-ui 地址&#xff1a;介绍 - Vant 4 (vant-ui.github.io) Vant 是一个轻量、可定制的移动端组件库 安装 通过 npm 安装&#xff1a; # Vue 3 项目&#xff0c;安装最新版 Vant npm i vant # Vue 2 项目&#xff0c;安装 Vant 2 npm i vantlatest-v…

数据可视化 pycharts实现中国各省市地图数据可视化

自用版 数据格式如下&#xff1a; 运行效果如下&#xff1a; import pandas as pd from pyecharts.charts import Map, TreeMap, Timeline, Page, WordCloud from pyecharts import options as opts from pyecharts.commons.utils import JsCode from pyecharts.globals im…

api接口1688商品详情接口采集商品详情数据商品价格详情页数据可支持高并发调用演示示例

接入1688商品详情API接口的步骤如下&#xff1a; 注册账号&#xff1a;首先&#xff0c;你需要在1688开放平台注册一个账号。 创建应用&#xff1a;登录后&#xff0c;在控制台中找到“我的应用”&#xff0c;点击“创建应用”。 获取API密钥&#xff1a;创建应用后&#xff…

C语言数据结构之二叉树

少年恃险若平地 独倚长剑凌清秋 &#x1f3a5;烟雨长虹&#xff0c;孤鹜齐飞的个人主页 &#x1f525;个人专栏 &#x1f3a5;前期回顾-栈和队列 期待小伙伴们的支持与关注&#xff01;&#xff01;&#xff01; 目录 树的定义与判定 树的定义 树的判定 树的相关概念 树的运用…

网络工程师必学知识:2、IPv4和IPv6地址划分

网络工程师必学知识&#xff1a;2、IPv4和IPv6地址划分 1.概述&#xff1a;2.IPv4&#xff1a;地址划分&#xff1a;有类划分&#xff0c;无类划分。一、有类划分&#xff1a;分为5类。ABCDE&#xff0c;掩码分别位8、16、24、28、27取值范围&#xff1a;出类别bit不变&#xf…

我是赵士杰,自述我的 Java 之旅:四年编码,千言万语中成长

你好我的朋友&#xff0c;请先容许我作一个简单介绍&#xff1a;我是赵士杰&#xff0c;一名 Java 攻城狮&#xff0c;欢迎关注我的微信公众号【技术人阿杰】。 不知不觉中&#xff0c;我在撰写技术博客领域已经投入了四年的精力&#xff0c;这也让我从一个默默无名之辈成长为了…

种草日记|林曦老师的冬日好物分享

冬天将尽春天就要来了&#xff0c;换季的时候最容易引起皮肤干燥、头发毛躁不舒服的问题&#xff0c;今天就来说说林曦老师推荐的冬日护理爱用好物。大家都要“如婴儿乎”&#xff0c;照顾好自己哦&#xff5e;      1、Aco甘油保湿霜    Aco甘油保湿霜好大一罐&#x…

《Vue3 基础知识》 使用 GoGoCod 升级到Vue3+ElementPlus 适配处理

此篇为 《Vue2ElementUI 自动转 Vue3ElementPlus&#xff08;GoGoCode&#xff09;》 的扩展&#xff01; Vue3 适配 Vue3 不兼容适配 Vue 3 迁移指南 在此&#xff0c;本章只讲述项目或组件库中遇到的问题&#xff1b; Vue3 移除 o n &#xff0c; on&#xff0c; on&#…

【Web前端实操21】商城官网_白色导航

今日份实现白色导航栏部分&#xff0c;也就是第三部分&#xff0c;效果如图中划线所示&#xff1a; 本次实现代码如之前的全局样式不再赘述&#xff0c;如有需要可以去我博客的Web前端实操19或者20自行查看。 本次主要更新mi.css和index.htm。 实现导航栏所需要的CSS样…

【图解面试】深入解析数据类型转换

将值从一种数据类型转换到另一种数据类型通常称为数据类型转换。在面试过程中大多数都是以代码输出题出现&#xff0c;但是要了解到具体的转换规则&#xff0c;彻底搞懂底层原理&#xff0c;才能应对变来变去的值类型~ 转布尔类型 Boolean类型有两个字面值&#xff1a; true …

调整Activation Function参数对神经网络的影响

目录 介绍&#xff1a; 数据集&#xff1a; 模型一&#xff08;tanh&#xff09; &#xff1a; 模型二&#xff08;relu&#xff09;&#xff1a; 模型三&#xff08;sigmoid&#xff09; &#xff1a; 模型四&#xff08;多层tanh&#xff09;&#xff1a; 模型五&am…

使用“快速开始”将数据传输到新的 iPhone 或 iPad

使用“快速开始”将数据传输到新的 iPhone 或 iPad 使用 iPhone 或 iPad 自动设置你的新 iOS 设备。 使用“快速开始”的过程会同时占用两台设备&#xff0c;因此请务必选择在几分钟内都不需要使用当前设备的时候进行设置。 确保你当前的设备已连接到无线局域网&#xff0c;并…

一篇带你彻底搞懂 Python 编程进阶之闭包

前言 在Python编程语言中&#xff0c;闭包是强大而灵活的语法&#xff0c;它为开发者提供了一种优雅而高效的方式来处理函数和代码结构。作为自动化测试和测试开发同学&#xff0c;弄懂它的作用及工作原理很有必要&#xff0c;面试中提及到的概率非常之大。 关于函数名的本质 …

APT攻击是什么?如何进行防护

随着网络技术的飞速发展&#xff0c;APT&#xff08;Advanced Persistent Threat&#xff09;攻击已经成为网络安全领域的一个重大问题。APT攻击是一种高度复杂的网络攻击&#xff0c;其目标是长期潜伏并逐步深入到目标网络中&#xff0c;以窃取敏感信息、破坏关键基础设施或制…

MyBatis 的注解实现方法

MyBatis 的注解实现方法 MyBatis 的注解实现方法引入依赖添加配置创建表创建实体类创建mapper接口InsertDeleteSelectResults和ResultMap通过配置文件解决 UpdateOptions MyBatis 的注解实现方法 引入依赖 在springBoot项目中下载了EditStarters插件的,可以直接在配置文件处右…

幻兽帕鲁怎么选择服务器

想要部署属于自己的幻兽帕鲁&#xff0c;首先需要拥有一台服务器&#xff0c;服务器是幻兽帕鲁运行的基础。游戏所需的服务器取决于游戏的规模、用户数量和功能需求。以下是一些通常需要考虑的服务器要求&#xff1a; 计算性能&#xff1a;包括cpu、内存、硬盘&#xff0c;cpu…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextPicker组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextPicker组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、TextPicker组件 TextClock组件通过文本将当前系统时间显示在设备上。支持不…

C++基础语法学习笔记

C Tutorial 1.基础语法 C 应用&#xff1a;操作系统、图形用户界面和嵌入式系统 C和C区别&#xff1a;C支持类和对象 C语法 #include <iostream> using namespace std;int main(){cout << "hello world!";return 0; }int main () { cout << &q…

vue之elementUi的el-select同时获取value和label的两种方法

一、通过ref的形式&#xff08;推荐&#xff09; <template><div class"root"><el-selectref"optionRef"v-model"value"placeholder"请选择"style"width: 250px"><el-optionv-for"item in optio…