Vue3学习记录(三)--- 组合式API之生命周期和模板引用

news2024/12/27 13:42:35

一、生命周期

1、简介

​ 生命周期,指的是一个 Vue 实例从创建到销毁的完整阶段,强调的是一个时间段。

​ 生命周期钩子函数,指的是 Vue 实例提供的内置函数,函数的参数为一个回调函数。这些钩子函数会在实例生命周期的某些固定时间点,依次按序执行其内部的回调函数。我们只需要在回调函数内部书写要执行的代码即可。

​ 在调用生命周期钩子函数时,Vue会自动将其回调函数注册到当前正在初始化 Vue 组件实例上,因此这些钩子函数应当在组件初始化时被同步注册,不可以在异步操作中调用这些钩子函数。因为当异步操作开始执行时,当前组件实例已经初始化完成,调用的钩子函数无法被注册到组件实例上。

​ 当然生命周期钩子函数也可以在一个外部函数中调用,只要调用栈是同步的,且最终起源自 <script setup> 就可以。

生周期图示:

在这里插入图片描述

2、生命周期钩子函数

​ 首先,在Vue3的组合式API中并不存在created()beforeCreate()这两个生命周期钩子函数,而是通过setup实现了更灵活的生命周期钩子函数,直接书写在<script setup>模块中的全局代码,相当于这两个钩子函数中的代码。

① onBeforeMount()
function onBeforeMount(callback: () => void): void

​ 该钩子函数会在组件实例被挂载到页面上之前被调用,此时组件中的响应式数据和函数方法等已经设置完成,可以在此阶段进行数据初始化计算操作。但此时组件中的DOM节点还没有被创建,此时无法操作DOM。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

<template>
  <div>
    <h1>{{ text }}</h1>
  </div>
</template>

<script setup>
// 引入要使用的模块 
import { ref, onBeforeMount } from 'vue'

// 声明一个响应式变量
let text = ref('这是一个大标题')
// 声明一个函数
const changeTest = (value) => {
  text.value = value
}
// 使用onBeforeMount()钩子函数
onBeforeMount(() => {
  // 调用响应变量
  console.log(text.value); // 这是一个大标题
  // 调用函数
  changeTest('这是修改后的大标题')
  console.log(text.value); // 这是修改后的大标题
  // 尝试操作dom 
  console.log(document.querySelector('h1')); // null 此时DOM还未渲染到页面上 无法被获取
})
</script>
② onMounted()
function onMounted(callback: () => void): void

​ 该生命周期钩子函数会在组件实例被挂载到页面上之后被调用,此时组件中的DOM结构和其同步子组件中的DOM结构都已经被挂载到页面上了,我们可以在此阶段进行 DOM 操作。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

// 承接上个案例的代码... 

// 引入要使用的模块 
import { ref, onBeforeMount, onMounted } from 'vue'

// 使用onMounted()钩子函数
onMounted(() => {
  // 调用响应变量
  console.log(text.value); // 这是修改后的大标题
  // 调用函数
  changeTest('这是再次修改后的大标题')
  console.log(text.value); // 这是再次修改后的大标题
  // 尝试操作dom 
  console.log(document.querySelector('h1')); // 成功获取DOM <h1>这是再次修改后的大标题</h1>
})

// 其他...
③ onBeforeUpdate()
function onBeforeUpdate(callback: () => void): void

​ 该钩子函数会在组件由于响应式状态变更,而引起的 DOM 树更新之前调用,此时获取DOM节点中的相关状态,还是未更新之前的状态;获取响应式状态,获取的是更新后的状态。我们可以在此阶段根据更新前后的数据状态进行相应操作。

​ 在onMounted()钩子函数中进行会引起DOM更新的响应式状态变更,也会触发当前钩子函数;在onBeforeMount()中的状态变更则不会,因为此时DOM结构还没有渲染到页面上。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

<template>
  <div>
    <h1>{{ text }}</h1>
    <button @click="changeTest('点击修改标题')">改变标题</button>
  </div>
</template>

<script setup>
// 引入要使用的模块 
import { ref, onBeforeUpdate } from 'vue'

// 声明一个响应式变量
let text = ref('这是一个大标题');

// 声明一个函数
const changeTest = (value) => {
  text.value = value
}

// 使用onBeforeUpdate()钩子函数
onBeforeUpdate(() => {
    // 输出变更后的响应式变量值
    console.log(text.value); // 点击修改标题
    // 获取 DOM 输出未更新的DOM状态值
    console.log(document.querySelector('h1').innerText) // 这是一个大标题
})
</script>
④ onUpdated()
function onUpdated(callback: () => void): void

​ 该钩子函数会在组件由于响应式状态变更,而引起的 DOM 树更新之后调用。此时获取DOM节点中的相关状态,获取的将是更新后的状态。这个钩子会在组件的 DOM 更新后被调用,这些更新可能是由不同的响应式状态变更引起的。

​ 不要在该阶段更改组件中的响应式状态,这肯有可能会导致无限死循环。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

<template>
  <div>
    <h1>{{ text }}</h1>
    <button @click="changeTest('点击修改标题')">改变标题</button>
  </div>
</template>

<script setup>
// 引入要使用的模块 
import { ref, onUpdated } from 'vue'

// 声明一个响应式变量
let text = ref('这是一个大标题');

// 声明一个函数
const changeTest = (value) => {
  text.value = value
}

// 使用onUpdated()钩子函数
onUpdated(() => {
    // 输出变更后的响应式变量值
    console.log(text.value); // 点击修改标题
    // 获取 DOM 输出更新后的DOM状态值
    console.log(document.querySelector('h1').innerText) // 点击修改标题
})
</script>
⑤ onBeforeUnmount()
function onBeforeUnmount(callback: () => void): void

​ 该钩子函数在组件实例被销毁之前调用,此时组件中的所有功能保持可用,可以在这一阶段做一些清理工作,例如取消订阅、清除定时器、释放资源等。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

// 引入要使用的模块 
import { onBeforeUnmount } from 'vue'

// 使用onBeforeUnmount()钩子函数
onBeforeUnmount(() => {
    // 做一些清理工作,释放占用的资源
})
⑥ onUnmounted()
function onUnmounted(callback: () => void): void

​ 该钩子函数在组件实例被销毁之后调用,此时当前组件的所有子组件都已经被卸载,且所有响应式状态(变量、计算属性、侦听器等)都停止作用了。这一阶段也可以做一些清理工作,例如取消订阅、清除定时器、释放资源等。但是尽量不要在该阶段进行一些耗时的操作,以免影响组件销毁的性能。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

案例代码:

// 引入要使用的模块 
import { onUnmounted } from 'vue'

// 使用onUnmounted()钩子函数
onUnmounted(() => {
    // 做一些清理工作,释放占用的资源
})
⑦ onActivated()
function onActivated(callback: () => void): void

​ 该钩子函数需要与<KeepAlive>结合使用,如果组件是<KeepAlive>中缓存组件的一部分,当组件被插入到DOM中时(包括首次挂载和从缓存重新挂载),会触发该钩子函数。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

⑧ onDeactivated()
function onDeactivated(callback: () => void): void

​ 该钩子函数需要与<KeepAlive>结合使用,如果组件是<KeepAlive>中缓存组件的一部分,当组件从DOM中被移除时(包括进入缓存和组件卸载),会触发该钩子函数。

​ 该钩子函数在服务端渲染期间不会被调用,只会在客户端执行。

⑨ onErrorCaptured()
function onErrorCaptured(callback: ErrorCapturedHook): void

type ErrorCapturedHook = (
  err: unknown,
  instance: ComponentPublicInstance | null,
  info: string
) => boolean | void

​ 该钩子函数会在捕获当前组件内的后代组件传递的错误时调用,错误源包括:组件渲染错误、事件处理器错误、侦听器错误等等。三个实参分别表示:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串。

​ 如果组件的继承链或组件链上存在多个 errorCaptured 钩子函数,对于同一个错误,这些钩子会被按从底至上的顺序,一一向上传递并调用errorCaptured 钩子函数。

​ 默认情况下,所有的错误都会被一层层向上传递,最终到达全局应用级的 app.config.errorHandler (前提是这个函数已经定义),如果我们在当前钩子函数中return false;,则会阻止错误向上传递,app.config.errorHandler 也无法监听到。

⑩ onRenderTracked()
function onRenderTracked(callback: DebuggerHook): void

type DebuggerHook = (e: DebuggerEvent) => void

type DebuggerEvent = {
  effect: ReactiveEffect
  target: object
  type: TrackOpTypes /* 'get' | 'has' | 'iterate' */
  key: any
}

​ 该钩子函数会在当前组件的组件模板渲染过程中追踪到响应式依赖时调用。且仅在开发模式下可用,在服务器端渲染期间不会被调用。

⑪ onRenderTriggered()
function onRenderTriggered(callback: DebuggerHook): void

type DebuggerHook = (e: DebuggerEvent) => void

type DebuggerEvent = {
  effect: ReactiveEffect
  target: object
  type: TriggerOpTypes /* 'set' | 'add' | 'delete' | 'clear' */
  key: any
  newValue?: any
  oldValue?: any
  oldTarget?: Map<any, any> | Set<any>
}

​ 该钩子函数会在当前组件内响应式依赖发生变更并触发了组件渲染时调用。且仅在开发模式下可用,在服务器端渲染期间不会被调用。

⑫ onServerPrefetch()
function onServerPrefetch(callback: () => Promise<any>): void

​ 该钩子函数,只会在当前组件示例在服务器上被渲染之前调用。

3、父子组件的生命周期钩子函数执行顺序
组件挂载阶段:

​ 在父组件和子组件同事挂载到页面上时,会按照以下顺序执行挂载阶段的钩子函数:

  • 父组件的<script setup>(相当于created()beforeCreate())。
  • 父组件的onBeforeMount()钩子函数。
  • 子组件的<script setup>(相当于created()beforeCreate())。
  • 子组件的onBeforeMount()钩子函数。
  • 子组件的onMounted()钩子函数。
  • 父组件的onMounted()钩子函数。
组件更新阶段:

​ 只有当父子组件同时发生更新时,两者的更新阶段钩子函数才会都被触发。如果单独只在父组件内发生更新或只在子组件内发生更新,则只会触发相应组件内的更新钩子函数。

  • 父组件的onBeforeUpdate()钩子函数。
  • 子组件的onBeforeUpdate()钩子函数。
  • 父组件的onUpdated()钩子函数。
  • 子组件的onUpdated()钩子函数。
组件销毁阶段:

​ 当父组件被销毁时,其内部的子组件也会一并被销毁,并按照以下顺序执行销毁阶段的钩子函数。

  • 父组件的onBeforeUnmount()钩子函数。
  • 子组件的onBeforeUnmount()钩子函数。
  • 子组件的onUnmounted()钩子函数。
  • 父组件的onUnmounted()钩子函数。

二、模板引用

1、简介

​ 模板引用是Vue提供给我们用来操作DOM的一种方法,通过为DOM元素设置一个ref attribute属性,并设置属性值为一个响应式变量,从而获取对该DOM元素的引用。然后就可以对获取的DOM进行操作,例如:获取焦点、改变样式等等。

​ 模板引用可以获取对普通DOM元素的引用,也可以获取对组件实例的引用。但只有当目标DOM渲染到页面上后,才可以通过响应式变量来获取该DOM的引用,并对其进行操作。

2、普通DOM的引用

​ 想要获取一个普通DOM的引用,首先需要声明一个响应式变量,然后将该变量的名字设置为目标DOM的ref 属性的属性值即可,最终就可以通过响应式变量来访问对应的DOM。

案例代码:
<template>
  <div>
    <!-- 给DOM元素增加一个ref属性 属性值与响应式变量名相同 -->
    <h1 ref="h1DOM">这是一个普通DOM</h1>
  </div>
</template>

<script setup>
import { ref, onBeforeMount, onMounted, watchEffect } from 'vue';
// 声明一个响应式变量 变量名与模板中的ref属性值相同
const h1DOM = ref(null);

watchEffect(() => {
  console.log('监听h1DOM属性值的变化----',h1DOM.value); // 初始为null 之后为对应DOM对象
})

onBeforeMount(() => {
  // onBeforeMount阶段DOM还未挂载,所以获取不到DOM
  console.log('beforeMount中获取模板引用----',h1DOM.value); // null
})

onMounted(() => {
  // onMounted阶段DOM已经挂载,可以获取到DOM
  console.log('onMounted中获取模板引用----',h1DOM.value); // 相应DOM
})
</script>
3、v-for列表渲染DOM的引用

v3.2.25 版本新增,可以通过模板引用,获取使用v-for进行列表渲染的DOM元素,获取结果为一个数组,包含列表渲染出来的所有元素,但是并不保证获取的元素数组的顺序与页面上元素的顺序相同。

​ 同样,首先需要声明一个响应式变量,然后将该变量的名字设置为目标DOM的ref 属性的属性值即可。

案例代码:
<template>
  <div>
    <!-- 给DOM元素增加一个ref属性 属性值与响应式变量名相同 -->
    <div v-for="item in 5" ref="domList">{{ item }}</div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
// 声明一个响应式变量 变量名与模板中的ref属性值相同
const domList = ref(null);


onMounted(() => {
  // onMounted阶段DOM已经挂载,可以获取到DOM
  console.log('onMounted中获取模板引用----',domList.value); // 列表渲染的所有DOM
  // 遍历domList中的所有DOM
  domList.value.forEach((item) => {
    console.log(item); // DOM
  })
})
</script>
4、模板引用函数

​ 除了给DOM的ref属性赋值一个响应式变量之外,还可以通过:动态给ref属性绑定一个函数,每次组件更新时,都会触发绑定的函数,绑定函数的第一个参数就是当前DOM的引用。

​ 当绑定元素被卸载时,ref绑定的函数也会被调用一次,不过此时表示DOM引用第一个参数值为null

案例代码:
<template>
  <div>
    <!-- 绑定函数 -->
    <input :ref="(el) => console.log('这是绑定了匿名函数的ref',el)" />
    <input :ref="test" />
  </div>
</template>

<script setup>
  
const test = (el) => {
  console.log('这是绑定js方法的ref----',el);
}
</script>

5、组件实例的引用

​ 当一个子组件加入的父组件中时,可以通过模板引用的方式,给其设置ref属性,从而获取到这个子组件的组件实例。

​ 如果这个子组件使用的是选项式API或者使用setup() 钩子函数的组合式API,则获取的组件实例与子组件的this完全相同,我们可以通过该组件实例访问子组件的每一个属性和方法,从而实现一些父子组件中的交互。当然这种方式并不推荐使用,因为可能会引起逻辑混乱,大多数情况下,还是推荐使用使用标准的 props 和 emit 接口来实现父子组件交互。

​ 但如果子组件使用的是<script setup>形式的组合式API,则该组件的属性和方法默认是私有的,默认情况下,获取的组件实例是无法访问组件中的任何属性和方法的。除非子组件通过defineExpose()宏方法(宏方法无需导入,可直接使用)主动向外暴露出一部分属性和方法,然后获取的组件实例才可以访问这些被主动暴露的属性和方法。

案例代码:

使用<script setup>形式的子组件Child.vue:

<template>
  <div> 
    <h3>这是一个子组件</h3>
  </div>
</template>

<script setup>
import {  ref } from 'vue'
// 声明一个响应式变量
const son = ref('我是script setup中的一个变量')
const son2 = ref('我是script setup中的一个暴露出来的变量')

// defineExpose 这样的编译器宏不需要导入
// 返回值会暴露给模板 能够被访问到
defineExpose({
  son2
})
</script>

使用setup() 钩子函数形式的子组件Child2.vue:

<template>
  <div>
    <h3>这是一个子组件</h3>
  </div>
</template>

<script>
// 引入响应式API
import { ref } from 'vue'

export default {
 // 使用setup()钩子函数
 setup() {
    // 声明响应式变量
    const son = ref('我是setup()钩子函数中的一个变量')
    // 返回值会暴露给模板和其他的选项式 API 
    return {
      son
    }
  },
};
</script>

使用选项式API的子组件Child3.vue:

<template>
  <div>
    <h3>这是一个子组件</h3>
  </div>
</template>

<script>
export default {
  name: 'ViteProjectChild',

  data() {
    return {
      son: '我是选项式API中的一个变量'
    };
  },
};
</script>

父组件:

<template>
  <div>
    <!-- 引入子组件 -->
    <Child ref="son1"></Child>
    <Child2 ref="son2"></Child2>
    <Child3 ref="son3"></Child3>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import Child from '../components/Child.vue';
import Child2 from '../components/Child2.vue';
import Child3 from '../components/Child3.vue';

const son1 = ref(null);
const son2 = ref(null);
const son3 = ref(null);


onMounted(() => {
  console.log('获取script setup的组合式API子组件----',son1.value); 
  console.log('获取script setup的组合式API子组件的属性----',son1.value.son);
  console.log('获取script setup的组合式API子组件的属性2----',son1.value.son2);
  console.log('获取setup()钩子函数的组合式API子组件----',son2.value); 
  console.log('获取setup()钩子函数的组合式API子组件的属性----',son2.value.son); 
  console.log('获取选项式API的子组件----',son3.value); 
  console.log('获取选项式API的子组件的属性----',son3.value.son);
})
</script>

页面效果:

在这里插入图片描述

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

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

相关文章

鸿蒙原生应用开发-ArkTS语言基础类库概述

ArkTS语言基础类库是HarmonyOS系统上为应用开发者提供的常用基础能力&#xff0c;主要包含能力如下图所示。 1.提供异步并发和多线程并发的能力。 支持Promise和async/await等标准的JS异步并发能力。 TaskPool为应用程序提供一个多线程的运行环境&#xff0c;降低整体资源的消耗…

互联网电商一站式服务——商品评论❀

API接口是一种商业软件开发工具&#xff0c;可以帮助开发者实现业务需求。通过 API接口&#xff0c;开发人员可以快速搭建自己的应用&#xff0c;实现数据采集分析和处理&#xff0c;也可以通过这个接口完成与其它系统的集成与通信。电商API就是各大电商平台提供给开发者访问平…

redis10 应用问题(穿透、击穿、雪崩、分布式锁)

思维草图 缓存穿透 查询不存在的数据&#xff0c;穿透redis缓存&#xff0c;请求直接攻击后端db。 问题 当系统中引入redis缓存后&#xff0c;一个请求进来后&#xff0c;会先从redis缓存中查询&#xff0c;缓存有就直接返回&#xff08;相当于一道隔离闸&#xff0c;保护db…

记录踩过的坑-macOS下使用VS Code

目录 切换主题 安装插件 方法1 方法2 搭建Python开发环境 装Python插件 配置解释器 打开项目 打开终端 INFO: pip is looking at multiple versions xxxx&#xff0c;过了很久后报错 方法1 方法2 ​​​​​​​ 切换主题 安装插件 方法1 方法2 搭建Python开发环境…

[Python人工智能] 四十二.命名实体识别 (3)基于Bert+BiLSTM-CRF的中文实体识别万字详解(异常解决中)

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解如何实现中文命名实体识别研究,构建BiGRU-CRF模型实现。这篇文章将继续以中文语料为主,介绍融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。然而,该代码最终结…

外汇天眼:投资房地产轻松获利12%?台湾上百人因「庞氏骗局」损失6000万

现代社会因为金融体系不断发展与改革&#xff0c;衍生出各式各样投资理财的形式与标的&#xff0c;其中房地产因为具有对抗通胀、满足居住需求的双重特性&#xff0c;一直被视为一种稳健的投资标的。 然而&#xff0c;日前竟有多位民众向媒体爆料&#xff0c;表示碰到非法吸金的…

基于springboot+vue的周边游平台个人管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

使用华为云云函数functiongraph

之前使用腾讯云serverless&#xff0c;但是突然开始收费了。所以改用functiongraph 首先登陆华为云。 目录 1.登录华为云 2.在控制台找到functiongraph并开通 3.添加依赖包&#xff1a; 3.1 制作依赖包 3.2引入依赖包 4.发送请求 4.1直接发送 4.1.1uri 4.1.2 请求头…

稀碎从零算法笔记Day7-LeetCode:罗马数字转整数

题型&#xff1a;字符串转化、找规律 链接&#xff1a;13. 罗马数字转整数 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 …

自然语言处理之语言模型(LM)介绍

自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;的一个重要分支&#xff0c;它旨在使计算机能够理解、解释和生成人类语言。在自然语言处理中&#xff0c;语言模型&…

拓尔微代理商 TMI3252T 600kHz 18V 2A同步COT降压转换器

TMI3252/S/T是高效率600kHz&#xff0c;恒定导通时间 &#xff08;COT&#xff09; 控制同步模式降压型DC-DC转换器&#xff0c;能够提供高达2A电流。TMI3252/S/T集成主要具有极低 RDS&#xff08;ON&#xff09; 的开关和同步开关以尽量减少传导损耗。低输出电压纹波和小尺寸的…

前端H5动态背景登录页面(上)

最近一段时间看一些关于前端的东西&#xff0c;下面分享两个非常不错的前端动态背景登陆页面&#xff0c;还有几个等后面有时间了再整理。 1、彩色气泡登录页面 下面是源代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8…

跨地域传文件时 面临的安全、效率等问题要如何解决?

近年来&#xff0c;企业在异国、异地设立分支机构的越来越多&#xff0c;在日常经营中&#xff0c;企业总部和分支机构间存在平行、垂直及互相交叉的管理模式和业务往来需求&#xff0c;因此&#xff0c;大型企业存在必然的跨地域传文件场景&#xff0c;比如跨地理域文件交换、…

VS2015报错:error MSB8020和MSB8036的解决方案

VS2015编译报错&#xff1a;error MSB8020 提示信息&#xff1a;error MSB8020: The build tools for v141 (Platform Toolset ‘v141’) cannot be found. To build using the v141 build tools, please install v141 build tools. Alternatively, you may upgrade to the c…

(MATLAB)第十二章-数列与极限

目录 12.1 数列 12.1.1 数列求和 1. 累计求和函数sum() 2. 忽略NaN累计求和函数 nansum() 3. 求此元素位置之前的元素和函数cumsum() 4. 求梯形累计和函数cumtrapz() 12.1.2 数列求积 1. 元素连续相乘函数 prod() 2. 求累计积函数 cumprod() 3. 阶乘函数 ffactorial(n…

中文文本分类_1(pytorch 实现)

import torch import torch.nn as nn import torchvision from torchvision import transforms, datasets import os, PIL, pathlib, warningswarnings.filterwarnings("ignore") # 忽略警告信息# win10系统 device torch.device("cuda" if torch.cuda.i…

【你刚好需要,我们刚好可以做到】戳!戳!戳!

你刚好需要&#xff0c;我们刚好可以做到&#xff01;&#xff01;&#xff01; 今天给大家介绍一个朋友的网络科技公司&#xff1a;天津集创科技有限公司。 这不仅仅是一家公司&#xff0c;更是一场变革的引领者。通过创新和前瞻性技术&#xff0c;创作打破传统&#xff0c;共…

医学与美学的聚能,雍禾医疗打造“好医生·一人一案”个性化服务

在当下社会&#xff0c;脱发问题已成为困扰许多人的头等大事。尤其是在年轻人群中&#xff0c;随着社会竞争的加剧和生活压力的增加&#xff0c;越来越多的年轻人意识到毛发对于个人形象的重要性。无论是在求职面试、社交场合还是日常生活中&#xff0c;浓密健康的头发都成为了…

分享一本好书《大模型应用开发极简入门:基于GPT-4和ChatGPT》

如果问个问题&#xff1a;有哪些产品曾经创造了伟大的奇迹&#xff1f;ChatGPT 应该会当之无愧入选。仅仅发布 5 天&#xff0c;ChatGPT 就吸引了 100 万用户——当然&#xff0c;数据不是关键&#xff0c;关键是其背后的技术开启了新的 AI 狂潮&#xff0c;成为技术变革的点火…