Vue3之script-setup全面解析

2023-05-16

可能很多同学(包括我)刚上手 Vue 3.0 之后,都会觉得开发过程似乎变得更繁琐了,Vue 官方团队当然不会无视群众的呼声,如果你基于脚手架和 .vue 文件开发,那么可以享受到更高效率的开发体验。

在阅读这篇文章之前,需要对 Vue 3.0 的单组件有一定的了解,如果还处于完全没有接触过的阶段,请先抽点时间阅读 单组件的编写 一章。

WARNING
本章节的部分方案属于实验性方案,或者是刚进入定稿阶段,所以在官网文档上还暂时看不到使用说明,期间可能还会有一些功能调整和 BUG 修复,请留意版本号说明。

所以要体验以下新特性,请确保项目下 package.json 里的 vue (opens new window)和 @vue/compiler-sfc (opens new window)都在 v3.1.4 版本以上,最好同步 NPM 上当前最新的 @next 版本,否则在编译过程中可能出现一些奇怪的问题(这两个依赖必须保持同样的版本号)。

#script-setup

这是一个比较有争议的新特性,作为 setup 函数的语法糖,褒贬不一,不过经历了几次迭代之后,目前在体验上来说,感受还是非常棒的。

TIP
截止至 2021-07-16 ,<script setup> 方案已在 Vue 3.2.0-beta.1 版本中脱离实验状态,正式进入 Vue 3.0 的队伍,在新的版本中已经可以作为一个官方标准的开发方案使用(但初期仍需注意与开源社区的项目兼容性问题,特别是 UI 框架)。

另外,Vue 的 3.1.2 版本是针对 script-setup 的一个分水岭版本,自 3.1.4 开始 script-setup 进入定稿状态,部分旧的 API 已被舍弃,本章节内容将以最新的 API 为准进行整理说明,如果您需要查阅旧版 API 的使用,请参阅 这里 (opens new window)。

#新特性的产生背景

在了解它怎么用之前,可以先了解一下它被推出的一些背景,可以帮助你对比开发体验上的异同点,以及了解为什么会有这一章节里面的新东西。

在 Vue 3.0 的 .vue 组件里,遵循 SFC 规范要求(注:SFC,即 Single-File Component,.vue 单组件),标准的 setup 用法是,在 setup 里面定义的数据如果需要在 template 使用,都需要 return 出来。

如果你使用的是 TypeScript ,还需要借助 defineComponent 来帮助你对类型的自动推导。

<!-- 标准组件格式 -->
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
// ...
return {
// ...
}
}
})
</script>

关于标准 setup 和 defineComponent 的说明和用法,可以查阅 全新的 setup 函数 一节。

script-setup 的推出是为了让熟悉 3.0 的用户可以更高效率的开发组件,减少一些心智负担,只需要给 script 标签添加一个 setup 属性,那么整个 script 就直接会变成 setup 函数,所有顶级变量、函数,均会自动暴露给模板使用(无需再一个个 return 了)。

Vue 会通过单组件编译器,在编译的时候将其处理回标准组件,所以目前这个方案只适合用 .vue 文件写的工程化项目。

<!-- 使用 script-setup 格式 -->
<script setup lang="ts">
// ...
</script>

对,就是这样,代码量瞬间大幅度减少……

TIP
因为 script-setup 的大部分功能在书写上和标准版是一致的,这里只提及一些差异化的表现。

#全局编译器宏

在 script-setup 模式下,新增了 4 个全局编译器宏,他们无需 import 就可以直接使用。

但是默认的情况下直接使用,项目的 eslint 会提示你没有导入,但你导入后,控制台的 Vue 编译助手又会提示你不需要导入,就很尴尬…

哈哈哈哈不过不用着急,可以配置一下 lint ,把这几个编译助手写进全局规则里,就可以了,不需要导入也不会报错了。

// 项目根目录下的 .eslintrc.js
module.exports = {
// 原来的lint规则,补充下面的globals...
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
}

关于几个宏的说明都在下面的文档部分有说明,你也可以从这里导航过去直接查看。

说明
defineProps点击查看
defineEmits点击查看
defineExpose点击查看
withDefaults点击查看

下面我们继续了解 script-setup 的变化。

#template 操作简化

如果使用 JSX / TSX 写法,这一点没有太大影响,但对于习惯使用 <template /> 的开发者来说,这是一个非常爽的体验。

主要体现在这两点:

#变量无需进行 return

标准组件模式下,setup 里定义的变量,需要 return 后,在 template 部分才可以正确拿到:

<!-- 标准组件格式 -->
<template>
<p>{{ msg }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
const msg: string = 'Hello World!';
// 要给 template 用的数据需要 return 出来才可以
return {
msg
}
}
})
</script>

在 script-setup 模式下,你定义了就可以直接使用。

<!-- 使用 script-setup 格式 -->
<template>
<p>{{ msg }}</p>
</template>
<script setup lang="ts">
const msg: string = 'Hello World!';
</script>

#子组件无需手动注册

子组件的挂载,在标准组件里的写法是需要 import 后再放到 components 里才能够启用:

<!-- 标准组件格式 -->
<template>
<Child />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
// 导入子组件
import Child from '@cp/Child.vue'
export default defineComponent({
// 需要启用子组件作为模板
components: {
Child
},
// 组件里的业务代码
setup () {
// ...
}
})
</script>

在 script-setup 模式下,只需要导入组件即可,编译器会自动识别并启用。

<!-- 使用 script-setup 格式 -->
<template>
<Child />
</template>
<script setup lang="ts">
import Child from '@cp/Child.vue'
</script>

#props 的接收方式变化

由于整个 script 都变成了一个大的 setup function ,没有了组件选项,也没有了 setup 入参,所以没办法和标准写法一样去接收 props 了。

这里需要使用一个全新的 API :defineProps 。

defineProps 是一个方法,内部返回一个对象,也就是挂载到这个组件上的所有 props ,它和普通的 props 用法一样,如果不指定为 prop, 则传下来的属性会被放到 attrs 那边去。

TIP
前置知识点:接收 props - 组件之间的通信。

#defineProps 的基础用法

所以,如果只是单纯在 template 里使用,那么其实就这么简单定义就可以了:

defineProps([
'name',
'userInfo',
'tags'
])

使用 string[] 数组作为入参,把 prop 的名称作为数组的 item 传给 defineProps 就可以了。

如果 script 里的方法要拿到 props 的值,你也可以使用字面量定义:

const props = defineProps([
'name',
'userInfo',
'tags'
])
console.log(props.name);

但在作为一个 Vue 老玩家,都清楚不显性的指定 prop 类型的话,很容易在协作中引起程序报错,那么应该如何对每个 prop 进行类型检查呢?

有两种方式来处理类型定义。

#通过构造函数检查 prop

这是第一种方式:使用 JavaScript 原生构造函数进行类型规定。

也就是跟我们平时定义 prop 类型时一样, Vue 会通过 instanceof 来进行 类型检查 (opens new window)。

使用这种方法,需要通过一个 “对象” 入参来传递给 defineProps ,比如:

defineProps({
name: String,
userInfo: Object,
tags: Array
});

所有原来 props 具备的校验机制,都可以适用,比如你除了要限制类型外,还想指定 name 是可选,并且带有一个默认值:

defineProps({
name: {
type: String,
required: false,
default: 'Petter'
},
userInfo: Object,
tags: Array
});

更多的 props 校验机制,可以点击 带有类型限制的 props 和 可选以及带有默认值的 props 了解更多。

#使用类型注解检查 prop

这是第二种方式:使用 TypeScript 的类型注解。

和 ref 等 API 的用法一样,defineProps 也是可以使用尖括号 <> 来包裹类型定义,紧跟在 API 后面,另外,由于 defineProps 返回的是一个对象(因为 props 本身是一个对象),所以尖括号里面的类型还要用大括号包裹,通过 key: value 的键值对形式表示,如:

defineProps<{ name: string }>();

注意到了吗?这里使用的类型,和第一种方法提到的指定类型时是不一样的。

TIP
在这里,不再使用构造函数校验,而是需要遵循使用 TypeScript 的类型。

比如字符串是 string,而不是 String 。

如果有多个 prop ,就跟写 interface 一样:

defineProps<{
name: string;
phoneNumber: number;
userInfo: object;
tags: string[];
}>();

其中,举例里的 userInfo 是一个对象,你可以简单的指定为 object,也可以先定义好它对应的类型,再进行指定:

interface UserInfo {
id: number;
age: number;
}
defineProps<{
name: string;
userInfo: UserInfo;
}>();

如果你想对某个数据设置为可选,也是遵循 TS 规范,通过英文问号 ? 来允许可选:

// name 是可选
defineProps<{
name?: string;
tags: string[];
}>();

如果你想设置可选参数的默认值,需要借助 withDefaults API。

WARNING
需要强调的一点是:在 构造函数 和 类型注解 这两种校验方式只能二选一,不能同时使用,否则会引起程序报错

#withDefaults 的基础用法

这个新的 withDefaults API 可以让你在使用 TS 类型系统时,也可以指定 props 的默认值。

它接收两个入参:

参数类型含义
propsobject通过 defineProps 传入的 props
defaultValuesobject根据 props 的 key 传入默认值

可能缺乏一些官方描述,还是看参考用法可能更直观:

withDefaults(defineProps<{
size?: number
labels?: string[]
}>(), {
size: 3,
labels: () => ['default label']
})

如果你要在 TS / JS 再对 props 进行获取,也可以通过字面量来拿到这些默认值:

// 如果不习惯上面的写法,你也可以跟平时一样先通过interface定义一个类型接口
interface Props {
msg?: string
}
// 再作为入参传入
const props = withDefaults(defineProps<Props>(), {
msg: 'hello'
})
// 这样就可以通过props变量拿到需要的prop值了
console.log(props.msg)

#emits 的接收方式变化

和 props 一样,emits 的接收也是需要使用一个全新的 API 来操作,这个 API 就是 defineEmits 。

和 defineProps 一样, defineEmits 也是一个方法,它接受的入参格式和标准组件的要求是一致的。

TIP
注意:从 3.1.3 版本开始,该 API 已被改名,加上了复数结尾,带有 s,在此版本之前是没有 s 结尾!

前置知识点:接收 emits - 组件之间的通信。

#defineEmits 的基础用法

由于 emit 并非提供给模板直接读取,所以需要通过字面量来定义 emits。

最基础的用法也是传递一个 string[] 数组进来,把每个 emit 的名称作为数组的 item 。

// 获取 emit
const emit = defineEmits(['chang-name']);
// 调用 emit
emit('chang-name', 'Tom');

由于 defineEmits 的用法和原来的 emits 选项差别不大,这里也不重复说明更多的诸如校验之类的用法了,可以查看 接收 emits 一节了解更多。

#attrs 的接收方式变化

attrs 和 props 很相似,也是基于父子通信的数据,如果父组件绑定下来的数据没有被指定为 props ,那么就会被挂到 attrs 这边来。

在标准组件里, attrs 的数据是通过 setup 的第二个入参 context 里的 attrs API 获取的。

// 标准组件的写法
export default defineComponent({
setup (props, { attrs }) {
// attrs 是个对象,每个 Attribute 都是它的 key
console.log(attrs.class);
// 如果传下来的 Attribute 带有短横线,需要通过这种方式获取
console.log(attrs['data-hash']);
}
})

但和 props 一样,由于没有了 context 参数,需要使用一个新的 API 来拿到 attrs 数据。

这个 API 就是 useAttrs 。

TIP
请注意,useAttrs API 需要 Vue 3.1.4 或更高版本才可以使用。

#useAttrs 的基础用法

顾名思义, useAttrs 可以是用来获取 attrs 数据的,它的用法非常简单:

// 导入 useAttrs 组件
import { useAttrs } from 'vue'
// 获取 attrs
const attrs = useAttrs()
// attrs是个对象,和 props 一样,需要通过 key 来得到对应的单个 attr
console.log(attrs.msg);

对 attrs 不太了解的话,可以查阅 获取非 Prop 的 Attribute

#slots 的接收方式变化

slots 是 Vue 组件的插槽数据,也是在父子通信里的一个重要成员。

对于使用 template 的开发者来说,在 script-setup 里获取插槽数据并不困难,因为跟标准组件的写法是完全一样的,可以直接在 template 里使用 <slot /> 标签渲染。

<template>
<div>
<!-- 插槽数据 -->
<slot />
<!-- 插槽数据 -->
</div>
</template>

但对使用 JSX / TSX 的开发者来说,就影响比较大了,在标准组件里,想在 script 里获取插槽数据,也是需要在 setup 的第二个入参里拿到 slots API 。

// 标准组件的写法
export default defineComponent({
// 这里的 slots 就是插槽
setup (props, { slots }) {
// ...
}
})

新版本的 Vue 也提供了一个全新的 useSlots API 来帮助 script-setup 用户获取插槽。

TIP
请注意,useSlots API 需要 Vue 3.1.4 或更高版本才可以使用。

#useSlots 的基础用法

先来看看父组件,父组件先为子组件传入插槽数据,支持 “默认插槽” 和 “命名插槽” :

<template>
<!-- 子组件 -->
<ChildTSX>
<!-- 默认插槽 -->
<p>I am a default slot from TSX.</p>
<!-- 默认插槽 -->
<!-- 命名插槽 -->
<template #msg>
<p>I am a msg slot from TSX.</p>
</template>
<!-- 命名插槽 -->
</ChildTSX>
<!-- 子组件 -->
</template>
<script setup lang="ts">
import ChildTSX from '@cp/context/Child.tsx'
</script>

在使用 JSX / TSX 编写的子组件里,就可以通过 useSlots 来获取父组件传进来的 slots 数据进行渲染:

// 注意:这是一个 .tsx 文件
import { defineComponent, useSlots } from 'vue'
const ChildTSX = defineComponent({
setup() {
// 获取插槽数据
const slots = useSlots()
// 渲染组件
return () => (
<div>
{/* 渲染默认插槽 */}
<p>{ slots.default ? slots.default() : '' }</p>
{/* 渲染命名插槽 */}
<p>{ slots.msg ? slots.msg() : '' }</p>
</div>
)
},
})
export default ChildTSX

#ref 的通信方式变化

在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,也就是父组件可以通过 childComponent.value.foo 这样的方式直接操作子组件的数据(参见:DOM 元素与子组件 - 响应式 API 之 ref)。

但在 script-setup 模式下,所有数据只是默认隐式 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。

在 script-setup 模式下,如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 defineExpose 来完成。

#defineExpose 的基础用法

defineExpose 的用法非常简单,它本身是一个函数,可以接受一个对象参数。

在子组件里,像这样把需要暴露出去的数据通过 key: value 的形式作为入参(下面的例子是用到了 ES6 的 属性的简洁表示法 (opens new window)):

<script setup lang="ts">
// 定义一个想提供给父组件拿到的数据
const msg: string = 'Hello World!';
// 显示暴露的数据,才可以在父组件拿到
defineExpose({
msg
});
</script>

然后你在父组件就可以通过挂载在子组件上的 ref 变量,去拿到暴露出来的数据了。

#顶级 await 的支持

在 script-setup 模式下,不必再配合 async 就可以直接使用 await 了,这种情况下,组件的 setup 会自动变成 async setup 。

<script setup lang="ts">
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>

它转换成标准组件的写法就是:

<script lang="ts">
import { defineComponent, withAsyncContext } from 'vue'
export default defineComponent({
async setup() {
const post = await withAsyncContext(
fetch(`/api/post/1`).then((r) => r.json())
)
return {
post
}
}
})
</script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue3之script-setup全面解析 的相关文章

  • OOM 很可怕吗 -- minio-client 上传文件触发 OOM 排错

    不要把 OOM 问题当作一个可怕的难题 xff0c 也许对着报错堆栈日志看代码就能解决 问题描述 线上服务出现 OOM 的日志 xff0c 日志显示是 minio client 的错误 使用 minio client 版本是 3 0 10
  • AI 写代码来了 - github 的 AI 写代码插件 copilot 发布

    以前老在调侃 AI 自动写代码 xff0c 没想到这么快就成现实 这几天 github 出了 AI 写代码插件 xff0c 支持 vscode 编辑器 xff0c js xff0c py xff0c go 等语言 xff0c 看了介绍 xf
  • 枚举与字符串的转换

    枚举类型的使用优势没啥好说的 但经常需要将它与字串进行转换方便显示或其它需求 1 将枚举中的标示转成字符串 xff1a define enumToString value 64 value 将枚举转换成字符串 2 在常见的方案中 xff0c
  • springcloud trace SDK 自研方案

    SDK 形式 xff0c 利用 threadlocal 实现 trace http grpc rabbitMQ springcloud gateway 异步线程池这类常见场景 客户端在协议 header 中增加 x request id x
  • fluent-bit 按 pod 名生成不同索引

    1 实现效果 如果 pod 名为 prod xff0c 输出索引名为 prod 2021 01 24 EFK 版本 xff1a es 7 12 fluent bit 1 7 5 kibana 7 12 2 实现方式 读取日志数据中 kube
  • jar 迁移 mvn 私有库

    将 jar 从一个 mvn 库迁移另一个 mvn 库的办法 1 拉取 jar 到本地 mvn 库 创建拉取项目文件夹 xff0c 文件夹下创建 pom xml xff0c settings xml 两个文件 xff0c 填写要迁移的 jar
  • Elasticsearch 解决 log4j 安全漏洞 - 升级镜像

    一 概论 Apache Log4j 2 被披露出存在严重代码执行漏洞 xff0c 目前官方已发布正式安全公告及版本 xff0c 漏洞编号 xff1a CVE 2021 44228 xff0c 漏洞被利用可导致服务器被入侵等危害 公司 ES
  • Prometheus 实现 podDown 实时告警

    一 需求 每个 pod 重启 删除时 xff0c 都能发出告警 要及时和准确 二 告警架构 集群部署在 k8s 上 xff0c 告警使用 Prometheus 43 alertManager 43 prometheusManager xff
  • prometheus 告警机制 -(为什么告警发的不及时)

    为什么告警有时发的及时 xff0c 有时发的慢 数据异常到监控发出告警的时间与多个参数相关 xff0c 包括采集间隔 xff0c 扫描间隔 xff0c group 发送间隔 xff0c 告警持续时间 for 等 最长的时间为 采集间隔 43
  • prometheus 告警机制 - 我的告警为什么重发

    为什么告警总在重复发 xff0c 有时不重复发 xff0c 怎么避免 告警会在两种情况下重发 告警 group 列表中告警有变更 xff08 增加或者减少 xff09 告警持续到 repeat interval 配置的重发时间 告警 gro
  • linux 盘格式化并挂载

    一 概论 如果 linux 要格式化盘 xff0c 需要先解挂 xff0c 才能格式化 xff0c 格式化的速度比 rm rf 会快 xff0c 作用一样 如果是初始化机器挂载盘 xff08 不要解绑操作 xff09 xff0c 直接查看第
  • grafana 画富集多个指标 label 的表格

    下午5点 xff1a 老哥 xff0c 今天把业务趋势图搞出来吧 一 怎么画表格 我们的需要是做下面的视图 xff0c 他是一个表格 xff0c 而且有着多个数据源 添加图表 填入数据 xff0c 展示原始图形 转换为 table 只显示最
  • [golang] 实现 jwt 方式登录

    1 Jwt 和 Session 登录方案介绍 JSON Web Token xff08 缩写 JWT xff09 是目前流行的跨域认证解决方案 原理是生存的凭证包含标题 header xff0c 有效负载 payload 和签名组成 用户信
  • Stochastic Light Culling for VPLs on GGX Microsurfaces论文研读

    前言 好久没写博客了 xff0c 今天来共享一下最近研读的一篇论文吧 xff0c 文章中 pdf 为参考文献可自行谷歌学术下载 因为本人还是个图形学菜鸟 xff0c 所以有什么问题希望大家多多指正 Stochastic Light Cull
  • 瞎更新,container_cpu_usage_seconds_total{job=“cadvisor“} 怎么没有啦

    一 基本介绍 1 1 概论 1 1 1 故事背景 今天在同步其他团队的 grafana 监控大盘时 xff0c Prometheus 服务报告说不能找到名为 container cpu usage seconds total job 61
  • Prometheus MySQL 性能监控

    一 介绍 Prometheus 是一种开源的监控系统和时序数据库 xff0c 旨在收集和处理大量数据并提供可视化 监控警报等功能 它支持多种语言 多种部署方式 xff0c 并且非常灵活 xff0c 而且社区支持非常活跃 xff0c 为用户提
  • 二、nodeJS 项目架构详解(app.js + Express + Http)

    参考 xff1a https www cnblogs com ostrich sunshine p 7474471 html 其中重点文件 文件夹说明 xff1a techNode xff1a bin www 启动运行 xff08 服务端口
  • centos 安装freeswitch

    首先安装freeswitch的运行库 更新yum yum update 安装依赖 yum install y git gcc c 43 43 wget alsa lib devel autoconf automake bison broad
  • Visio、Matlab高清图片插入word文档的几种方法。

    2023 3 30 直接参考这两个就行了 xff0c 不用花里胡哨的 MATLAB 1 重要的第一步 xff0c 另存为png图片 xff1b 2 导出之前先设置分辨率 xff0c 很多期刊要求600dpi 这一步很关键 Visio 1 重
  • CTF Crypto---RSA NC不互素

    题目 span class token keyword from span Crypto span class token punctuation span Util span class token punctuation span nu

随机推荐

  • 看一看Ubuntu的目录结构

    先了解一下Ubuntu的目录结构 xff0c 对于后面学习Ubuntu软件安装和使用都有帮助 一 Linux没有盘符这个概念 Windows存在多个驱动器盘符 xff0c 每个盘符形成多个树形并列的情形 xff0c Linux没有盘符这个概
  • 【C语言】——结构体进阶:结构体的内存对齐(超详细)

    前言 xff1a 上一篇已经讲了结构体的基本用法 相信各位小伙伴以经学会怎么使用 但是还有一个问题没有弄明白 结构体到底多大 xff0c 占内存空间多不多 xff0c 以经系统到底怎么访问结构体内的数据的 接下来 xff0c 详细分析一下结
  • [OpenCV实战]15 基于深度学习的目标跟踪算法GOTURN

    目录 1 什么是对象跟踪和GOTURN 2 在OpenCV中使用GOTURN 3 GOTURN优缺点 4 参考 在这篇文章中 xff0c 我们将学习一种基于深度学习的目标跟踪算法GOTURN GOTURN在Caffe中搭建 xff0c 现在
  • **在Linux的shell脚本里激活conda 虚拟环境**

    在Linux的shell脚本里激活conda 虚拟环境 之前突发其想 xff0c 既然在命令行可以通过conda activate tf激活tf的虚拟环境 xff0c 那么能不能写个脚本实现呢 xff1f 费了好大劲 xff0c 发现并不行
  • Hierarchical Russian Roulette for Vertex Connections论文研读

    第二篇论文研读文章了 xff0c 虽然依旧很菜 xff0c 但这一篇开始就相对轻松一点了 文档种有些问题 xff0c 其中所有 实时 应该替换为 高效 Hierarchical Russian Roulette for Vertex Con
  • ARM通用中断控制器GIC之中断控制

    在阅读本章之前 xff0c 可以参考笔者之前关于GIC的一些描述 xff1a ARM通用中断控制器GIC generic Interrupt Controller 简介 ARM架构Generic Interrupt Controller G
  • 最小生成树之Kruskal算法

    给定一个无向图 xff0c 如果它任意两个顶点都联通并且是一棵树 xff0c 那么我们就称之为生成树 Spanning Tree 如果是带权值的无向图 xff0c 那么权值之和最小的生成树 xff0c 我们就称之为最小生成树 MST Min
  • xcode11解决:xcode multiple commands produce .../xxx/Assets.car

    最近在xcode 11上使用pod碰到一个问题 xff0c Assets car被生成多次 问题如下 xff1a Multiple commands produce 39 Users luowei Library Developer Xco
  • 算法 —— 冒泡排序

    冒泡排序 冒泡排序是比较两个相邻元素 xff0c 如果它们不符合预期的顺序就交换的一个排序过程 冒泡排序就像水中气泡上升到水面的运动一样 xff0c 数组的每个元素在每次迭代中都把当前迭中最大 或最小 的元素移动到最后 xff0c 因此被称
  • UICollectionView viewForSupplementaryElementOfKind 不调用

    发现UICollectionView 的 方法不调用 func collectionView collectionView UICollectionView viewForSupplementaryElementOfKind kind St
  • UICollectionViewCell 自动大小的两种常用方式

    方法一 xff1a 自动计算 override func viewDidLoad super viewDidLoad if let flowLayout 61 collectionView collectionViewLayout as U
  • UITableViewCell 图片自适应

    常见的一种方法是异步Completed时 xff0c 根据图片大小计算cell的高度并缓存到字典里后 xff0c 刷新tableView或indexPath 但这里介绍另一种更好的方式是使用约束处理 xff0c 对imageView的上下左
  • Swift编译死锁问题

    最近在Swift OC混编项目里遇到个奇怪的问题 xff0c 这样一行代码尽然引发了Swift编译过程死锁 xxSwiftModel salary 61 xxOCModel salary doubleValue 如果哪位大神知道根因 xff
  • 多线程及聊天室程序

    1 一个多线程程序 新建一个 win32 console application 取名 xff1a MultiThread 选空的工程 xff0c 并建立一个名为 MultiThread 的源文件编辑 xff1a include inclu
  • SQL Server 2008语句大全完整版

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 设置内存选项 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • Swift从相册选择图片,图文混排并且可以保存、上传数据

    博主最近突发奇想想做一个自己的日记本App xff0c 在过程中遇到了一些坑 xff0c 摸索了很久才做出一个简单的日记本功能 先来看看一下效果吧 xff1a 先来说说这次用到的一些东西吧 xff1a 1 UIImagePickerCont
  • 2022年ABC模块样题十套分享

    2022年ABC模块样题十套分享 样题分享传送门
  • C# WinForm基础

    1 WinForm基础 Form1 cs using System using System Collections Generic using System ComponentModel using System Data using S
  • 做独立开发的一些感想

    好久没在CSDN上写东西 xff0c 这次写点感想吧 想想自己独立开发也有好多年了 xff0c 从刚毕业做的在线销售系统 xff0c 再到spring boot做写的my finances xff0c 再后来转iOS做的万能输入法 我的浏览
  • Vue3之script-setup全面解析

    可能很多同学 xff08 包括我 xff09 刚上手 Vue 3 0 之后 xff0c 都会觉得开发过程似乎变得更繁琐了 xff0c Vue 官方团队当然不会无视群众的呼声 xff0c 如果你基于脚手架和 vue 文件开发 xff0c 那么