Vue3新特性
Vue3新特性
- 1、Composition API
- 1.1 什么是 Composition API
- 1.2 常用 Composition API
- 1.2.1 setup
- 1.2.2 ref
- 1.2.3 reactive
- 1.2.4 computed
- 1.2.5 watchEffect、watchPostEffect、watchSyncEffect
- 1.2.6 watch
- 2、生命周期
- 2.1 Vue3生命周期钩子
- 2.2 vue2 和 vue3 关于生命周期的对比
- 3、异步组件
- 4、自定义指令
- 5、Teleport
- 6、自定义 Hooks
1、Composition API
1.1 什么是 Composition API
- 函数式编程,逻辑复用途经–函数组合(组合式 Composition API)
- 面对对象编程,逻辑复用的途径–继承(选项式 选项式 API )
函数式编程思想将组件 UI逻辑 和状态逻辑解耦,让组件得到更大的复用性
vue2 选项式API
export default {// data() 返回的属性将会成为响应式的状态// 并且暴露在 `this` 上data() {return {count: 0}},methods: {increment() {this.count++}},
}
</script>
Vue3 组合式(更拥抱这种写法)
<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)//或者const count = reactive({value:0})
// 用来修改状态、触发更新的函数
function increment() {count.value++
}
</script>
1.2 常用 Composition API
Q1: 说说你对 setup 的理解
- 组合式 API 的入口
Q2: ref 和 reactive 有什么区别?
- ref 内部使用了 reactive
- ref(obj) === reactive({ value: obj })
Q3: ref 和 shallowRef 的区别,以及 reactive 和 shallowReactive 的区别?
- shallow 表示浅层,这里均是指的响应值作用在第一层,即 .value,不过我们可以使用 triggerRef(xxx) 来在深层内容变更后,手动触发更新,需要注意的是 shallowReactive 没有对应方法
Q4: watchEffect 与 watch 的区别
- watch 是懒执行,属性改变的时候执行,而 watchEffect 是默认会执行一次,然后属性改变也会执行。
- watch 是需要传入侦听的数据源,而 watchEffect 是自动收集数据源作为依赖;
- watch 可以访问侦听状态变化前后的值,而 watchEffect 没有。
1.2.1 setup
setup() 钩子是在组件中使用组合式 API 的入口
<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)//或者const count = reactive({value:0})
// 用来修改状态、触发更新的函数
function increment() {count.value++
}
</script>
或
<script >
import { h, ref } from 'vue'export default {setup(props, { expose }) {const count = ref(0)const increment = () => ++count.value// 透传 Attributes(非响应式的对象,等价于 $attrs)console.log(context.attrs)// 插槽(非响应式的对象,等价于 $slots)console.log(context.slots)// 触发事件(函数,等价于 $emit)console.log(context.emit)// 暴露公共属性(函数)console.log(context.expose)expose({increment})return () => h('div', count.value)}
}
</script>
1.2.2 ref
ref 函数 用于定义一个响应式对象
<script setup>
import { ref, onMounted } from 'vue'
// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)
onMounted(() => {input.value.focus()
})
</script><template><input ref="input" />
</template>
1.2.3 reactive
用法同 ref
const obj = reactive({ count: 0 })
obj.count++
1.2.4 computed
const count = ref(1)
const plusOne = computed(() => count.value + 1)console.log(plusOne.value) // 2plusOne.value++ // 错误
或者通过对象 get、set 指定的方式
const count = ref(1)
const plusOne = computed({get: () => count.value + 1,set: (val) => {count.value = val - 1}
})plusOne.value = 1
console.log(count.value) // 0
1.2.5 watchEffect、watchPostEffect、watchSyncEffect
后两者是前者的语法糖,就是将第二个参数中的 flush,指定为对应值,分别为:flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
初始化 执行顺序:watchEffect,watchSyncEffect,watchPostEffect
变化时 执行顺序:watchSyncEffect,watchEffect,watchPostEffect
监听回调又叫监听副作用。
简单使用
const count = ref(0)watchEffect(() => console.log(count.value))
// -> 输出 0count.value++
// -> 输出 1
具有清除与停止侦听的功能
const stop = watchEffect(async (onCleanup) => {const { response, cancel } = doAsyncWork(id.value)// `cancel` 会在 `id` 更改时调用// 以便取消之前// 未完成的请求onCleanup(cancel)data.value = await response
})// 什么时候需要停止的话,那就
stop()
1.2.6 watch
先来简单回顾一下vue2.x版本中watch的使用
watch: {dataName (val, oldVal){console.log("改变前的数据-" + oldVal, "改变后的数据-" + val)}
}
Vue3中的watch
watch 自定义监听
watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调。
<template><button @click="change">count is: {{ state.count }}</button>
</template><script>
import { reactive, watch } from 'vue'
export default {setup () {let state = reactive({count: 0})let change = () => state.count++;watch(state, () => {console.log(state, '改变')})return { state, change }}
}
</script>
注意上面的代码,第一个参数传入的 state 对象
,第二个参数是回调函数
,只要 state 中任意的属性发生改变都会执行回调函数,和 vue2 的区别是不要写 deep 属性,默认就是深度监听了。
监听state 对象,没有旧的值,只有新的值
现在是监听整个对象,当然我们也可以监听对象上的某个属性,注意下面代码的写法:第一个是回调函数
,第二个参数也是回调函数
。
监听state 对象上的某个属性,有旧的值,有新的值
<template><button @click="change">count is: {{ state.count }}</button>
</template><script>
import { reactive, watch } from 'vue'
export default {setup () {let state = reactive({count: 0})let change = () => state.count++;watch(() => state.count, (oldVlaue, newValue) => {//() => state.count, getter方式console.log(oldVlaue, newValue, '改变')})return { state, change }}
}
</script>
上面都是以创建响应式对象函数reactive()方式定义的数据,下面再看看使用ref()初始化的数据怎样实现数据监听
<template><button @click="change">count is: {{ count }}</button>
</template><script>
import { reactive, watch } from 'vue'
export default {setup () {let count = ref(0)let change = () => count.value++;watch(count, () => {console.log(count.value '改变')})return { count , change }}
}
</script>
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {/* ... */
})
2、生命周期
2.1 Vue3生命周期钩子
- setup() : 开始创建组件之前,在
beforeCreate
和created
之前执行,创建的是data
和
method
- onBeforeMount() : 组件挂载到节点上之前执行的函数;
- onRenderTracked() : 响应式的收集依赖;追踪,订阅
- onMounted() : 组件挂载完成后执行的函数;
- onRenderTriggered() : 响应式的触发依赖变更,发布
- onBeforeUpdate(): 组件更新之前执行的函数;
- onUpdated(): 组件更新完成之后执行的函数;
- onBeforeUnmount(): 组件卸载之前执行的函数;
- onUnmounted(): 组件卸载完成后执行的函数;
- onActivated(): 被包含在
<keep-alive>
中的组件,会多出两个生命周期钩子函数,被激活时执行; - onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;
- onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。
PS: 使用<keep-alive>
组件会将数据保留在内存中,比如我们不想每次看到一个页面都重新加载数据,就可以使用<keep-alive>
组件解决。
2.2 vue2 和 vue3 关于生命周期的对比
3、异步组件
当我们的项目达到一定的规模时,对于某些组件来说,我们并不希望一开始全部加载,而是需要的时候进行加载;这样的做得目的可以很好的提高用户体验。
一般用于分割代码,按需加载
为了实现这个功能,Vue3中为我们提供了一个方法,即defineAsyncComponent
,这个方法可以传递两种类型的参数,分别是函数类型
和对象类型
传递工厂函数作为参数
<template><logo-img /><hello-world msg="Welcome to Your Vue.js App" />
</template><script setup>
import LogoImg from './components/LogoImg.vue'
import HelloWorld from './components/HelloWorld.vue'
</script>
现在我们就将组件修改为异步组件,示例代码如下:
<template><logo-img /><hello-world msg="Welcome to Your Vue.js App" />
</template><script setup>
import { defineAsyncComponent } from 'vue'
import LogoImg from './components/LogoImg.vue'// 简单用法
const HelloWorld = defineAsyncComponent(() =>import('./components/HelloWorld.vue'),
)
</script>
传递对象类型作为参数
defineAsyncComponent方法也可以接收一个对象作为参数,该对象中有如下几个参数:
- loader:同工厂函数;
- loadingComponent:加载异步组件时展示的组件;
- errorComponent:加载组件失败时展示的组件;
- delay:显示loadingComponent之前的延迟时间,单位毫秒,默认200毫秒;
- timeout:如果提供了timeout,并且加载组件的时间超过了设定值,将显示错误组件,默认值为Infinity(单位毫秒);
- suspensible:异步组件可以退出控制,并始终控制自己的加载状态。具体可以参考文档;
- onError:一个函数,该函数包含4个参数,分别是error、retry、fail和attempts,这4个参数分别是错误对象、重新加载的函数、加载程序结束的函数、已经重试的次数。
<template><logo-img /><hello-world msg="Welcome to Your Vue.js App" />
</template><script setup>
import { defineAsyncComponent } from 'vue'
import LogoImg from './components/LogoImg.vue'
import LoadingComponent from './components/loading.vue'
import ErrorComponent from './components/error.vue'// 定义一个耗时执行的函数,t 表示延迟的时间, callback 表示需要执行的函数,可选
const time = (t, callback = () => {}) => {return new Promise(resolve => {setTimeout(() => {callback()resolve()}, t)})
}
// 记录加载次数
let count = 0
const HelloWorld = defineAsyncComponent({// 工厂函数loader: () => {return new Promise((resolve, reject) => {;(async function () {await time(300) //模拟异步const res = await import('./components/HelloWorld.vue')if (++count < 3) {// 前两次加载手动设置加载失败reject(res)} else {// 大于3次成功resolve(res)}})()})},loadingComponent: LoadingComponent,errorComponent: ErrorComponent,delay: 0,timeout: 1000,suspensible: false,onError(error, retry, fail, attempts) {// 注意,retry/fail 就像 promise 的 resolve/reject 一样:// 必须调用其中一个才能继续错误处理。if (attempts < 3) {// 请求发生错误时重试,最多可尝试 3 次console.log(attempts)retry()} else {fail()}},
})
</script>
通常会与 Suspense 配合
用Suspense 包一下异步组件,用来在组件树中协调对异步依赖的处理。该特性目前还不是稳定版本,后续可能会有变更。
4、自定义指令
- 自定义指令着眼于组件,围绕组件去做增强
- composition api着眼于状态,围绕数据做功能增强
我们都知道指令是为了增强组件的,我们常见的指令有:v-if、v-show、v-model、v-bind:value、v-on:click 等。
自定义指令其实非常简单,我们需要始终关注以下几个问题:
- 指令的钩子函数,有点类似生命周期函数钩子
- 指令钩子函数中的参数
- 指令的逻辑处理
注册自定指令,有点像封装了一个组件,封装在外部。有点类似vue2的mixin(功能复用),不过比mixin好很多,没mixin那么多缺点。
自定义指令关注组件或者本身dom(如 v-if,作用于dom节点)。composition api更关注状态
自定义指令 v-focus 、v-drag案例
<template><input v-focus /><div class="heyi" v-drag></div>
</template><script setup lang="ts">
// 注册自定义指令
import { vDrag } from "../directives/vDrag";
import { vFocus } from "../directives/vFocus";
</script><style scoped>
.heyi {width: 100px;height: 100px;background-color: red;
}
</style>
vDrag组件
import { Directive } from "vue";//ts// mixin xxxxxxexport const vDrag: Directive = {mounted(el) {//el,当前domel.draggable = true;el.addEventListener("dragstart", () => {console.log("dragstart");});},
};
vFocus组件
import { Directive } from "vue";// mixin xxxxxxexport const vFocus: Directive = {//tsmounted(el) {el.focus();},
};
指令钩子:
const myDirective = {// 在绑定元素的 attribute 前// 或事件监听器应用前调用created(el, binding, vnode, prevVnode) {// 下面会介绍各个参数的细节},// 在元素被插入到 DOM 前调用beforeMount(el, binding, vnode, prevVnode) {},// 在绑定元素的父组件// 及他自己的所有子节点都挂载完成后调用mounted(el, binding, vnode, prevVnode) {},// 绑定元素的父组件更新前调用beforeUpdate(el, binding, vnode, prevVnode) {},// 在绑定元素的父组件// 及他自己的所有子节点都更新后调用updated(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载前调用beforeUnmount(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载后调用unmounted(el, binding, vnode, prevVnode) {}
}
5、Teleport
该特性允许你将组件内的某个子组件挂载到任意 HTML 节点上,这个特性像极了 React 中的 createPortal。
整个vue应用都是挂载到根节点,然后下面子组件挂到父组件上行成一棵树。
假设我现在某一个组件想挂到别的地方去,而不是父组件上,就使用Teleport
假设不用Teleport
<template><div class="heyi"></div>
</template><script setup lang="ts"></script><style scoped>
.heyi {width: 100px;height: 100px;background-color: red;position: absolute;left: 0;top: 0;
}
</style>
打开控制台查看,会发现 <div class="heyi"></div>
挂在我们的vue实例 #app底下,也就是正常的父级dom下面
使用了Teleport
<template><Teleport to="body"><div class="heyi"></div></Teleport>
</template><script setup lang="ts"></script><style scoped>
.heyi {width: 100px;height: 100px;background-color: red;position: absolute;left: 0;top: 0;
}
</style>
打开控制台查看,会发现 <div class="heyi"></div>
挂在body地下,不再是#app底下
- Teleport 组件创建
- 首先会在在主视图里插入注释节点或者空白文本节点
- 接着获取目标元素节点
- 最后调用mount方法创建子节点往目标元素插入 Teleport 组件的子节点
Teleport通常用来创建模态框modal
- 弹出层
- Popover 等
- tooltip
6、自定义 Hooks
假设我们需要封装一个计数器,该计数器用于实现数字的增加或者减少,并且我们可以指定数字可最大和最小值
使用:(负责视图)
<template><div><p>{{ current }} [max: 10; min: 1;]</p><div class="contain"><button @click="inc()">Inc()</button><button @click="dec()" style="margin-left: 8px">Dec()</button><button @click="set(3)" style="margin-left: 8px">Set(3)</button><button @click="reset()" style="margin-left: 8px">Reset()</button></div></div>
</template><script lang="ts" setup>import { useCounter } from './useCounter'const [current, { inc, dec, set, reset }] = useCounter(20, { min: 1, max: 10 })
</script>
useCounter就是自定义 Hooks(负责状态)
import { Ref, readonly, ref } from 'vue'// 判断是否为数字
const isNumber = (value: unknown): value is number => typeof value === 'number'export interface UseCounterOptions {/*** Min count*/min?: number/*** Max count*/max?: number
}export interface UseCounterActions {/*** Increment, default delta is 1* @param delta number* @returns void*/inc: (delta?: number) => void/*** Decrement, default delta is 1* @param delta number* @returns void*/dec: (delta?: number) => void/*** Set current value* @param value number | ((c: number) => number)* @returns void*/set: (value: number | ((c: number) => number)) => void/*** Reset current value to initial value* @returns void*/reset: () => void
}export type ValueParam = number | ((c: number) => number)function getTargetValue(val: number, options: UseCounterOptions = {}) {const { min, max } = optionslet target = valif (isNumber(max)) {target = Math.min(max, target)}if (isNumber(min)) {target = Math.max(min, target)}return target
}function useCounter(initialValue = 0,options: UseCounterOptions = {},
): [Ref<number>, UseCounterActions] {const { min, max } = optionsconst current = ref(getTargetValue(initialValue, {min,max,}),)const setValue = (value: ValueParam) => {const target = isNumber(value) ? value : value(current.value)current.value = getTargetValue(target, {max,min,})return current.value}const inc = (delta = 1) => {setValue(c => c + delta)}const dec = (delta = 1) => {setValue(c => c - delta)}const set = (value: ValueParam) => {setValue(value)}const reset = () => {setValue(initialValue)}return [readonly(current),{inc,dec,set,reset,},]
}export default useCounter
总结:Composition API的优点:将组件 UI逻辑 和状态逻辑解耦,让组件得到更大的复用性
相关文章:

Vue3新特性
Vue3新特性 1、Composition API1.1 什么是 Composition API1.2 常用 Composition API1.2.1 setup1.2.2 ref1.2.3 reactive1.2.4 computed1.2.5 watchEffect、watchPostEffect、watchSyncEffect1.2.6 watch 2、生命周期2.1 Vue3生命周期钩子2.2 vue2 和 vue3 关于生命周期的对比…...

一套功能齐全、二开友好的即时通讯IM工具,提供能力库和UI库,支持单聊、频道和机器人(附源码)
前言 在当今数字化时代,即时通讯(IM)和实时音视频(RTC)功能已成为众多应用的标配。然而,现有的解-决方案往往存在一些痛点,如架构落后、成本高昂、数据安全性和隐私保护不足,以及二次开发和部署的复杂性。 为了解决这些问题&…...

MySQL:JOIN 多表查询
多表查询 在关系型数据库中,表与表之间是有联系的,它们通过 外键 联系在一起,所以在实际应用中,经常使用多表查询。多表查询就是同时查询两个或两个以上的表。 MySQL多表查询是数据库操作中非常重要的一部分,它允许你…...

【机器学习】必会算法模型之:一文掌握 密度聚类,建议收藏。
密度聚类 1、引言2、密度聚类2.1 定义2.2 核心原理2.3 实现步骤2.4 算法公式2.5 代码示例 3、总结 1、引言 在机器学习的无监督学习领域,聚类是一项基础而重要的任务。 聚类算法通过将数据点分组,使同一组内的数据点具有更大的相似性,而组间…...

代码:前端与数据库交互的登陆界面
<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>登录</title> </head> <body>…...

发电机基础知识:负载组
什么是发电机负载组? 简单地说,负载组是一种可以产生人工电力负载的设备,用于测试发电机并验证发电机组的性能,包括相关组件,以确保通过使发电机发动机达到适当的工作温度和压力来满足适当的负载。 它是如何工作的&a…...

内网安全:各类密码的抓取
Mimikatz在线读取SAM文件 离线读取SAM文件 在线读取lsass进程 离线读取lsass进程 BrowserGhost浏览器密码抓取 Sharp-HackBrowserData浏览器密码抓取 SharpDecryptPwd数据库密码抓取 LaZagne各类密码的抓取 Windows其他类型抓NTLM Hash工具 sam文件和lsass进程就是Wind…...
前端面试题汇总2
1. CSS 中两个 .class1 .class2 从哪个开始解析 在 CSS 中,选择器 .class1 .class2 表示所有 class 为 class1 的元素中的 class 为 class2 的子元素。浏览器解析这个选择器时,从右向左解析。也就是说,浏览器首先找到所有 class 为 class2 的…...

分布式服务框架zookeeper+消息队列kafka
一、zookeeper概述 zookeeper是一个分布式服务框架,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:命名服务,状态同步,配置中心,集群管理等。 在分布式环境下,经常需要对应用/服…...

服务攻防-应用协议cve
Cve-2015-3306 背景: ProFTPD 1.3.5中的mod_copy模块允许远程攻击者通过站点cpfr和site cpto命令读取和写入任意文件。 任何未经身份验证的客户端都可以利用这些命令将文件从文件系统的任何部分复制到选定的目标。 复制命令使用ProFTPD服务的权限执行,…...

Springcloud之gateway的使用详解
官网地址:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/ 1.网关入门 helloword 网关不依赖start-web 导入的pom: <!--gateway--> <dependency><groupIdorg.springframework.cloud</groupId><arti…...

中望CAD 建筑 v2024 解锁版下载、安装教程 (超强的CAD三维制图)
前言 中望CAD建筑版是一款国产CAD制图软件,专注于建筑设计领域。中望CAD建筑版拥有丰富多样的建筑图块和图案,完美兼容各类建筑图纸。同时,它提供了绘图标准规范,使绘图更加规范和专业。更值得一提的是,该软件还具备智…...

windows edge自带的pdf分割工具(功能)
WPS分割pdf得会员,要充值!网上一顿乱找,发现最简单,最好用,免费的还是回到Windows。 Windows上直接在edge浏览器打开PDF,点击 打印 按钮,页面下选择对应页数 打印机 选择 另存为PDF,然后保存就…...

HTML5实现好看的天气预报网站源码
文章目录 1.设计来源1.1 获取天气接口1.2 PC端页面设计1.3 手机端页面设计 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_4…...

比较(八)利用python绘制指示器
比较(八)利用python绘制指示器 指示器(Indicators)简介 指示器是一系列相关图的统称,主要用于突出展示某一变量的实际值与目标值的差异,例如常见的数据delta、仪表盘、子弹图、水滴图等。 快速绘制 基于p…...

【体外诊断】ARM/X86+FPGA嵌入式计算机在医疗CT机中的应用
体外诊断 信迈科技提供基于Intel平台、AMD平台、NXP平台的核心板、2.5寸主板、Mini-ITX主板、4寸主板、PICO-ITX主板,以及嵌入式准系统等计算机硬件。产品支持GAHDMI等独立双显,提供丰富串口、USB、GPIO、PCIe扩展接口等I/O接口,扩展性强&…...

力扣 28找到字符串中第一个匹配项的下标 KMP算法
思路: 朴素匹配有很多步骤是多余的 KMP算法能够避免重复匹配 KMP算法主要是根据子串生成的next数组作为回退的依据,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。 这里讲一下为什么用模式串的最大公共前后缀…...
JavaScript(10)——匿名函数
匿名函数 没有名字的函数,无法直接使用。 使用方式: 函数表达式立即执行函数 函数表达式 将匿名函数赋值给一个变量,并且通过变量名称进行调用 let fn function(){ 函数体 } 调用: fn() 立即执行函数 语法: (function () {…...

图片上传成功却无法显示:静态资源路径配置问题解析
1、故事的背景 最近,有个学弟做了一个简单的后台管理页面。于是他开始巴拉巴拉撘框架,写代码,一顿操作猛如虎,终于将一个简单的壳子搭建完毕。但是在实现功能:点击头像弹出上传图片进行头像替换的时候,卡壳…...

【转盘案例-弹框-修改Bug-完成 Objective-C语言】
一、我们来看示例程序啊 1.旋转完了以后,它会弹一个框,这个框,是啥, Alert 啊,AlertView 也行, AlertView,跟大家说过,是吧,演示过的啊,然后,我们就用iOS9来做了啊,完成了以后,我们要去弹一个框, // 弹框 UIAlertController *alertController = [UIAlertContr…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...
用鸿蒙HarmonyOS5实现国际象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的国际象棋小游戏的完整实现代码,使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├── …...