Vue3-Composition-API(二)

一、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.mfbz.cn/a/363670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring实现事务(一)

Spring事务 .什么是事务事务的操作Spring中事务的实现准备工作创建表创建项目,引入Spring Web, Mybatis, mysql等依赖配置文件实体类 编程式事务(手动写代码操作事务)声明式事务(利用注解自动开启和提交事务) . 什么是事务 事务是⼀组操作的集合, 是⼀个不可分割的操作 在我们…

基于布谷鸟搜索的多目标优化matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 1. 布谷鸟搜索算法基础 2. 多目标优化问题 3. 基于布谷鸟搜索的多目标优化算法 4. 解的存储和选择策略 5.算法步骤 5.完整程序 1.程序功能描述 基于布谷鸟搜索的多目标优化&#xff0c;…

JavaScript基础(二)—— 运算符、表达式与语句(if、switch、循环)

学习目标&#xff1a; 掌握常见运算符&#xff0c;为程序“能思考”做准备 掌握分支语句&#xff0c;让程序具备判断能力 掌握循环语句&#xff0c;让程序具备重复执行能力 一、运算符 1. 赋值运算符 对变量进行赋值的运算符&#xff0c;能够使用赋值运算符简化代码。 …

【解决视网膜长尾数据】关系子集学习、射击法、加权知识蒸馏

长尾分布下的视网膜&#xff1a;关系子集学习、射击法、加权知识蒸馏 核心思想问题&#xff1a;类别分布的不平衡问题问题&#xff1a;共现标签问题&#xff1a;特定区域和特征的类别关联解法&#xff1a;划分子集解决样本不平衡问题解法&#xff1a;射击法解决共现标签问题解法…

【缓存周总结】Redis缓存的使用以及数据安全的处理

前言 Redis非关系型数据库已经是很常见的工具了&#xff0c;项目中用到的也很多&#xff0c;这篇文章系统的分析下使用过程中可能会遇到的问题 一、缓存 缓存是数据交换的缓冲区&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高。 我们项目中引用的Redis目的就是…

Unity - 调节camera物理相机参数(HDRP)

在 “Hierarchy” 右键 -> Volume -> Global Volume new 一个 profile, 设置Mode为Pysical Camera 再点击camera组件&#xff0c;这时候设置 ISO、Shutter Speed、Aperture等参数值还会有效。

深入了解如何对IPA包进行有效的混淆处理

1、安装混淆工具 首先电脑上要安装ipagurad工具&#xff0c;官网链接&#xff1a;IpaGuard官网--IOS 应用程序ipa文件混淆加密保护工具 2、生成混淆文件 由于混淆需要首先 打开要处理的IPA文件 第一项&#xff0c;填写我们需要重签名的 ipa 路径&#xff08;当前导入的路径跟导…

跟着pink老师前端入门教程-day16

二十七、CSS3进阶 1、CSS3 2D转换 转换&#xff08;transform&#xff09;是CSS3中具有颠覆性的特征之一&#xff0c;可以实现元素的位移、旋转、缩放等效果 转换&#xff08;transform&#xff09;可以简单理解为变形 移动&#xff1a;translate&#xff1b;旋转&#xff…

【LVGL源码移植】

LVGL源码移植 ■ LVGL源码移植一&#xff1a;下载LVGL源码二&#xff1a;修改LVGL文件夹1: 将这5个文件&#xff0c;复制到一个新的文件夹2: 简化文件&#xff0c;减少内存消耗&#xff08;去除不必要的文件&#xff09;3: 为了规范化&#xff0c;我们将下列文件进行重命名 三&…

nodejs+vue+ElementUi宠物领养救助网站0w6wc

宠物领养救助平台采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的nodejs进行编写&#xff0c;使用了vue框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对用户、宠物类别、宠物…

七、并发工具(上)

一、自定义线程池 1&#xff09;背景&#xff1a; 在 QPS 量比较高的情况下&#xff0c;我们不可能说所有的访问都创建一个线程执行&#xff0c;这会导致内存占用过高&#xff0c;甚至有可能出现 out of memory另外也要考虑 cpu 核数&#xff0c;如果请求超过了cpu核数&#…

【多个SpringBoot模块项目如何变成聚合项目】

【前言】 项目虽然是Eureka、OpenFeign 进行服务注册和服务调用&#xff0c;但是每个模块都是一个单独的SpringBoot&#xff0c;启动每个模块都需要单独启动一个idea,觉得这个过于繁琐&#xff0c;现在想把项目变成一个聚合项目&#xff0c;只需要启动一个idea即可。 【过程】…

09. 异常处理

目录 1、前言 2、常见的异常 3、异常处理try...except...finally 4、异常信息解读 5、raise 6、自定义异常 7、小结 1、前言 在编程中&#xff0c;异常&#xff08;Exception&#xff09;是程序在运行期间检测到的错误或异常状况。当程序执行过程中发生了一些无法继续执…

vue前端html导出pdf

package.json中添加依赖 调用方&#xff1a; import htmlToPdf from ../../../utils/file/htmlToPdf.js// 下载方法&#xff0c;pdfDownloadDpi为onClickDownLoad() {htmlToPdf.getPdf(标题1, jsfgyzcpgxmShow, this.pdfDownloadDpi)}htmlToPdf.js // 页面导出为pdf格式 imp…

Backtrader 文档学习- Broker - Cheat-On-Open

Backtrader 文档学习- Broker - Cheat-On-Open 1.概述 V1.9.44.116增加了Cheat On Open的支持。对于全押的人来说&#xff0c;这似乎是一个必需的功能&#xff0c;用bar的收盘价后进行计算&#xff0c;希望与开盘价相匹配。 当开盘价差距&#xff08;上涨或下跌&#xff0c;取…

杂题——试题-算法训练-P0602

分析&#xff1a; 把要重排序的数字转成数组对数组进行排序&#xff0c;从小到大排序数组转成字符串&#xff0c;字符串转成数字&#xff0c;得到最小数再把最小数的字符串反转&#xff0c;得到最大数注意&#xff1a; 在java语言中&#xff0c;如果使用Arrays.toString(digits…

DevOps系列文章之 Git命令:过滤日志

使用git log命令查找特定提交历史的高级技巧。其中的一些技巧配合格式化日志命令使用有奇效。 按照数量过滤 使用git log命令时最基本的过滤方式就是按照可以显示的日志条数进行过滤。如果你只对最近几次提交感兴趣&#xff0c;这会节省在页面上查看所有提交的麻烦。 git lo…

成熟的汽车制造供应商协同平台 要具备哪些功能特性?

汽车行业是一个产业链长且“重”的行业&#xff0c;整个业务流程包括了研发、设计、采购、库存、生产、销售、售后等一系列环节&#xff0c;在每一个环节都涉及到很多信息交换的需求。对内要保证研发、采购、营销等业务环节信息流通高效安全&#xff0c;对外要与上、下游合作伙…

springboot-前后端分离——第一篇

本篇主要对前后端分离的一些基础知识进行总结&#xff0c;主要对HTTP请求协议、HTTP响应格式、Http协议解析等进行总结。重点在于简单了解前端如何向服务端发送请求&#xff0c;服务端如何接收请求并返回响应结果。 一、简单案例&#xff1a; 首先创建一个springboot项目&…

使用pygame建立一个简单的使用键盘方向键移动的方块小游戏

import pygame import sys# 初始化pygame pygame.init()# 设置窗口大小 screen_size (640, 480) # 创建窗口 screen pygame.display.set_mode(screen_size) # 设置窗口标题 pygame.display.set_caption("使用键盘方向键移动的方块的简单小游戏")# 设置颜色 bg_colo…
最新文章