VUE3 指令 插槽

news2024/12/23 8:42:42

指令

指令是 Vue 模板语法里的特殊标记,在使用上和 HTML 的 data-* 属性十分相似,统一以 v- 开头( e.g. v-html )。

它以简单的方式实现了常用的 JavaScript 表达式功能,当表达式的值改变的时候,响应式地作用到 DOM 上。

内置指令
vue 提供了一些内置指令可以直接使用,例如:

<template>
  <!-- 渲染一段文本 -->
  <span v-text="msg"></span>

  <!-- 渲染一段 HTML -->
  <div v-html="html"></div>

  <!-- 循环创建一个列表 -->
  <ul v-if="items.length">
    <li v-for="(item, index) in items" :key="index">
      <span>{{ item }}</span>
    </li>
  </ul>

  <!-- 一些事件( `@` 等价于 `v-on`-->
  <button @click="hello">Hello</button>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const msg = ref<string>('Hello World!')
    const html = ref<string>('<p>Hello World!</p>')
    const items = ref<string[]>(['a', 'b', 'c', 'd'])

    function hello() {
      console.log(msg.value)
    }

    return {
      msg,
      html,
      items,
      hello,
    }
  },
})
</script>

内置指令在使用上都非常的简单,可以在官方文档的 内置指令 一章查询完整的指令列表和用法,在模板上使用时,请了解 指令的模板语法 。

TIP

有两个指令可以使用别名:

v-on 的别名是 @ ,使用 @click 等价于 v-on:click
v-bind 的别名是 : ,使用 :src 等价于 v-bind:src

自定义指令
如果 Vue 的内置指令不能满足业务需求,还可以开发自定义指令。
相关的 TS 类型
在开始编写代码之前,先了解一下自定义指令相关的 TypeScript 类型。

自定义指令有两种实现形式,一种是作为一个对象,其中的写法比较接近于 Vue 组件,除了 getSSRProps 和 deep 选项 外,其他的每一个属性都是一个 钩子函数 ,下一小节会介绍钩子函数的内容。

// 对象式写法的 TS 类型
// ...
export declare interface ObjectDirective<T = any, V = any> {
  created?: DirectiveHook<T, null, V>
  beforeMount?: DirectiveHook<T, null, V>
  mounted?: DirectiveHook<T, null, V>
  beforeUpdate?: DirectiveHook<T, VNode<any, T>, V>
  updated?: DirectiveHook<T, VNode<any, T>, V>
  beforeUnmount?: DirectiveHook<T, null, V>
  unmounted?: DirectiveHook<T, null, V>
  getSSRProps?: SSRDirectiveHook
  deep?: boolean
}
// ...

另外一种是函数式写法,只需要定义成一个函数,但这种写法只在 mounted 和 updated 这两个钩子生效,并且触发一样的行为。

// 函数式写法的 TS 类型
// ...
export declare type FunctionDirective<T = any, V = any> = DirectiveHook<
  T,
  any,
  V
>
// ...

这是每个钩子函数对应的类型,它有 4 个入参:

// 钩子函数的 TS 类型
// ...
export declare type DirectiveHook<
  T = any,
  Prev = VNode<any, T> | null,
  V = any
> = (
  el: T,
  binding: DirectiveBinding<V>,
  vnode: VNode<any, T>,
  prevVNode: Prev
) => void
// ...

钩子函数第二个参数的类型:

// 钩子函数第二个参数的 TS 类型
// ...
export declare interface DirectiveBinding<V = any> {
  instance: ComponentPublicInstance | null
  value: V
  oldValue: V | null
  arg?: string
  modifiers: DirectiveModifiers
  dir: ObjectDirective<any, V>
}
// ...

可以看到自定义指令最核心的就是 “钩子函数” 了,接下来来了解这部分的知识点。
钩子函数
和 组件的生命周期 类似,自定义指令里的逻辑代码也有一些特殊的调用时机,在这里称之为钩子函数:
在这里插入图片描述

TIP

因为自定义指令的默认写法是一个对象,
所以在代码风格上是遵循 Options API 的生命周期命名,
而非 Vue 3 的 Composition API 风格。

钩子函数在用法上就是这样子:

const myDirective = {
  created(el, binding, vnode, prevVnode) {
    // ...
  },
  mounted(el, binding, vnode, prevVnode) {
    // ...
  },
  // 其他钩子...
}

在 相关的 TS 类型 已了解,每个钩子函数都有 4 个入参:

在这里插入图片描述
其中用的最多是 el 和 binding 了。

el 的值就是通过 document.querySelector 拿到的那个 DOM 元素。

binding 是一个对象,里面包含了以下属性:
在这里插入图片描述
在了解了指令的写法和参数作用之后,来看看如何注册一个自定义指令。
局部注册
自定义指令可以在单个组件内定义并使用,通过和 setup 函数 同级别的 directives 选项进行定义,可以参考下面的例子和注释:

<template>
  <!-- 这个使用默认值 `unset` -->
  <div v-highlight>{{ msg }}</div>

  <!-- 这个使用传进去的黄色 -->
  <div v-highlight="`yellow`">{{ msg }}</div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  // 自定义指令在这里编写,和 `setup` 同级别
  directives: {
    // `directives` 下的每个字段名就是指令名称
    highlight: {
      // 钩子函数
      mounted(el, binding) {
        el.style.backgroundColor =
          typeof binding.value === 'string' ? binding.value : 'unset'
      },
    },
  },
  setup() {
    const msg = ref<string>('Hello World!')

    return {
      msg,
    }
  },
})
</script>

上面是对象式的写法,也可以写成函数式:

export default defineComponent({
  directives: {
    highlight(el, binding) {
      el.style.backgroundColor =
        typeof binding.value === 'string' ? binding.value : 'unset'
    },
  },
})

TIP

局部注册的自定义指令,默认在子组件内生效,子组件内无需重新注册即可使用父组件的自定义指令。

全局注册

自定义指令也可以注册成全局,这样就无需在每个组件里定义了,只要在入口文件 main.ts 里启用它,任意组件里都可以使用自定义指令。

请查看 开发本地 Vue 专属插件 一节的内容了解如何注册一个全局的自定义指令插件。

deep 选项

除了 钩子函数 ,在 相关的 TS 类型 里还可以看到有一个 deep 选项,它是一个布尔值,作用是:

如果自定义指令用于一个有嵌套属性的对象,并且需要在嵌套属性更新的时候触发 beforeUpdate 和 updated 钩子,那么需要将这个选项设置为 true 才能够生效。

<template>
  <div v-foo="foo"></div>
</template>

<script lang="ts">
import { defineComponent, reactive } from 'vue'

export default defineComponent({
  directives: {
    foo: {
      beforeUpdate(el, binding) {
        console.log('beforeUpdate', binding)
      },
      updated(el, binding) {
        console.log('updated', binding)
      },
      mounted(el, binding) {
        console.log('mounted', binding)
      },
      // 需要设置为 `true` ,如果是 `false` 则不会触发
      deep: true,
    },
  },
  setup() {
    // 定义一个有嵌套属性的对象
    const foo = reactive({
      bar: {
        baz: 1,
      },
    })

    // 2s 后修改其中一个值,会触发 `beforeUpdate` 和 `updated`
    setTimeout(() => {
      foo.bar.baz = 2
      console.log(foo)
    }, 2000)

    return {
      foo,
    }
  },
})
</script>

插槽

Vue 在使用子组件的时候,子组件在 template 里类似一个 HTML 标签,可以在这个子组件标签里传入任意模板代码以及 HTML 代码,这个功能就叫做 “插槽” 。

默认插槽

默认情况下,子组件使用 标签即可渲染父组件传下来的插槽内容,例如:

在父组件这边:

<template>
  <Child>
    <!-- 注意这里,子组件标签里面传入了 HTML 代码 -->
    <p>这是插槽内容</p>
  </Child>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import Child from '@cp/Child.vue'

export default defineComponent({
  components: {
    Child,
  },
})
</script>


在子组件这边:

<template>
  <slot />
</template>

默认插槽非常简单,一个 就可以了。

具名插槽
有时候可能需要指定多个插槽,例如一个子组件里有 “标题” 、 “作者”、 “内容” 等预留区域可以显示对应的内容,这时候就需要用到具名插槽来指定不同的插槽位。

子组件通过 name 属性来指定插槽名称:

<template>
  <!-- 显示标题的插槽内容 -->
  <div class="title">
    <slot name="title" />
  </div>

  <!-- 显示作者的插槽内容 -->
  <div class="author">
    <slot name="author" />
  </div>

  <!-- 其他插槽内容放到这里 -->
  <div class="content">
    <slot />
  </div>
</template>

父组件通过 template 标签绑定 v-slot:name 格式的属性,来指定传入哪个插槽里:

<template>
  <Child>
    <!-- 传给标题插槽 -->
    <template v-slot:title>
      <h1>这是标题</h1>
    </template>

    <!-- 传给作者插槽 -->
    <template v-slot:author>
      <h1>这是作者信息</h1>
    </template>

    <!-- 传给默认插槽 -->
    <p>这是插槽内容</p>
  </Child>
</template>

v-slot:name 有一个别名 #name 语法,上面父组件的代码也相当于:

<template>
  <Child>
    <!-- 传给标题插槽 -->
    <template #title>
      <h1>这是标题</h1>
    </template>

    <!-- 传给作者插槽 -->
    <template #author>
      <h1>这是作者信息</h1>
    </template>

    <!-- 传给默认插槽 -->
    <p>这是插槽内容</p>
  </Child>
</template>

TIP

在使用具名插槽的时候,子组件如果不指定默认插槽,
那么在具名插槽之外的内容将不会被渲染。

默认内容
可以给 slot 标签添加内容,例如 默认内容 ,当父组件没有传入插槽内容时,会使用默认内容来显示,默认插槽和具名插槽均支持该功能。

注意事项
有一条规则需要记住:

父组件里的所有内容都是在父级作用域中编译的
子组件里的所有内容都是在子作用域中编译的

CSS 样式与预处理器

Vue 组件的 CSS 样式部分,Vue 3 保留着和 Vue 2 完全一样的写法。

编写组件样式表

最基础的写法,就是在 .vue 文件里添加一个 style 标签,即可在里面写 CSS 代码了。

<template>
  <div>
    <!-- HTML 代码 -->
  </div>
</template>

<script lang="ts">
  // TypeScript 代码
</script>

<style>
/* CSS 代码 */
.msg {
  width: 100%;
}
.msg p {
  color: #333;
  font-size: 14px;
}
</style>

动态绑定 CSS

动态绑定 CSS ,在 Vue 2 就已经存在了,在此之前常用的是 :class 和 :style ,现在在 Vue 3 ,还可以通过 v-bind 来动态修改了。

使用 :class 动态修改样式名
它是绑定在 DOM 元素上面的一个属性,跟 class=“class-name” 这样的属性同级别,它非常灵活!

TIP

使用 :class 是用来动态修改样式名,
也就意味着必须提前把样式名对应的样式表先写好!

假设已经提前定义好了这几个变量:

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const activeClass = 'active-class'
    const activeClass1 = 'active-class1'
    const activeClass2 = 'active-class2'
    const isActive = true

    return {
      activeClass,
      activeClass1,
      activeClass2,
      isActive,
    }
  },
})
</script>

如果只想绑定一个单独的动态样式,可以传入一个字符串:

<template>
  <p :class="activeClass">Hello World!</p>
</template>

如果有多个动态样式,也可以传入一个数组:

<template>
  <p :class="[activeClass1, activeClass2]">Hello World!</p>
</template>

还可以对动态样式做一些判断,这个时候传入一个对象:

<template>
  <p :class="{ 'active-class': isActive }">Hello World!</p>
</template>

多个判断的情况下,记得也用数组套起来:

<template>
  <p :class="[{ activeClass1: isActive }, { activeClass2: !isActive }]">
    Hello World!
  </p>
</template>

那么什么情况下会用到 :class 呢?

最常见的场景,应该就是导航、选项卡了,比如要给一个当前选中的选项卡做一个突出高亮的状态,那么就可以使用 :class 来动态绑定一个样式。

<template>
  <ul class="list">
    <li
      class="item"
      :class="{ cur: index === curIndex }"
      v-for="(item, index) in 5"
      :key="index"
      @click="curIndex = index"
    >
      {{ item }}
    </li>
  </ul>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const curIndex = ref<number>(0)

    return {
      curIndex,
    }
  },
})
</script>

<style scoped>
.cur {
  color: red;
}
</style>

这样就简单实现了一个点击切换选项卡高亮的功能。

使用 :style 动态修改内联样式

如果觉得使用 :class 需要提前先写样式,再去绑定样式名有点繁琐,有时候只想简简单单的修改几个样式,那么可以通过 :style 来处理。

默认的情况下,都是传入一个对象去绑定:

1.key 是符合 CSS 属性名的 “小驼峰式” 写法,或者套上引号的短横线分隔写法(原写法),例如在 CSS 里,定义字号是 font-size ,那么需要写成 fontSize 或者 ‘font-size’ 作为它的键。

2.value 是 CSS 属性对应的 “合法值”,比如要修改字号大小,可以传入 13px 、0.4rem 这种带合法单位字符串值,但不可以是 13 这样的缺少单位的值,无效的 CSS 值会被过滤不渲染。

<template>
  <p
    :style="{
      fontSize: '13px',
      'line-height': 2,
      color: '#ff0000',
      textAlign: 'center',
    }"
  >
    Hello World!
  </p>
</template>

如果有些特殊场景需要绑定多套 style,需要在 script 先定义好各自的样式变量(也是符合上面说到的那几个要求的对象),然后通过数组来传入:

<template>
  <p :style="[style1, style2]">Hello World!</p>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const style1 = {
      fontSize: '13px',
      'line-height': 2,
    }
    const style2 = {
      color: '#ff0000',
      textAlign: 'center',
    }

    return {
      style1,
      style2,
    }
  },
})
</script>

使用 v-bind 动态修改 style
当然,以上两种形式都是关于 script 和 template 部分的操作,如果觉得会给模板带来一定的维护成本的话,不妨考虑这个新方案,将变量绑定到 style 部分去。

TIP

请注意这是一个在 3.2.0 版本之后才被归入正式队列的新功能!
如果需要使用它,请确保的 vue 的版本号在 3.2.0 以上,
最好是保持最新版本。

先来看看基本的用法:

<template>
  <p class="msg">Hello World!</p>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const fontColor = ref<string>('#ff0000')

    return {
      fontColor,
    }
  },
})
</script>

<style scoped>
.msg {
  color: v-bind(fontColor);
}
</style>

如上面的代码,将渲染出一句红色文本的 Hello World!

这其实是利用了现代浏览器支持的 CSS 变量来实现的一个功能(所以如果打算用它的话,需要提前注意一下兼容性噢,点击查看:CSS Variables 兼容情况 )。

它渲染到 DOM 上,其实也是通过绑定 style 来实现,可以看到渲染出来的样式是:

<p class="msg" data-v-7eb2bc79="" style="--7eb2bc79-fontColor:#ff0000;">
  Hello World!
</p>

对应的 CSS 变成了:

.msg[data-v-7eb2bc79] {
  color: var(--7eb2bc79-fontColor);
}

理论上 v-bind 函数可以在 Vue 内部支持任意的 JavaScript 表达式,但由于可能包含在 CSS 标识符中无效的字符,因此官方是建议在大多数情况下,用引号括起来,如:

.text {
  font-size: v-bind('theme.font.size');
}

由于 CSS 变量的特性,因此对 CSS 响应式属性的更改不会触发模板的重新渲染(这也是和 :class 与 :style 的最大不同)。

TIP

不管有没有开启 <style scoped> ,使用 v-bind 渲染出来的 CSS 变量,都会带上 scoped 的随机 hash 前缀,避免样式污染(永远不会意外泄漏到子组件中),所以请放心使用!

如果对 CSS 变量的使用还不是很了解的话,可以先阅读一下相关的基础知识点。

相关阅读:使用 CSS 自定义属性(变量) - MDN

样式表的组件作用域

CSS 不像 JS ,是没有作用域的概念的,一旦写了某个样式,直接就是全局污染。所以 BEM 命名法 等规范才应运而生。

但在 Vue 组件里,有两种方案可以避免出现这种污染问题:一个是 Vue 2 就有的 style scoped ,一个是 Vue 3 新推出的 style module 。

Style Scoped

Vue 组件在设计的时候,就想到了一个很优秀的解决方案,通过 scoped 来支持创建一个 CSS 作用域,使这部分代码只运行在这个组件渲染出来的虚拟 DOM 上。

使用方式很简单,只需要在 style 上添加 scoped 属性:

<!-- 注意这里多了一个 `scoped` -->
<style scoped>
.msg {
  width: 100%;
}
.msg p {
  color: #333;
  font-size: 14px;
}
</style>

编译后,虚拟 DOM 都会带有一个 data-v-xxxxx 这样的属性,其中 xxxxx 是一个随机生成的 Hash ,同一个组件的 Hash 是相同并且唯一的:

<div class="msg" data-v-7eb2bc79>
  <p data-v-7eb2bc79>Hello World!</p>
</div>

而 CSS 则也会带上与 HTML 相同的属性,从而达到样式作用域的目的。

.msg[data-v-7eb2bc79] {
  width: 100%;
}
.msg p[data-v-7eb2bc79] {
  color: #333;
  font-size: 14px;
}

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

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

相关文章

1x1卷积、Inception网络

目录1.1x1卷积(1x1 convolution)又称网络中的网络(network in network)池化层只能压缩图像的宽和高&#xff0c;1x1卷积能压缩通道数量&#xff0c;减少计算成本。如上图&#xff0c;输入维度的通道数为192&#xff0c;用32个1x1x192的filters&#xff0c;就能将输出的通道数压…

java基础—面试题一

文章目录1.和equals区别是什么&#xff1f;2.Java中的 <<、>>、>>> 是什么3.if-else-if-else与switch的区别4.while和do-while的区别5.switch 是否能作用在 byte 上&#xff0c;是否能作用在 long 上&#xff0c;是否能作用在String上6.&和&&…

大数据技术架构(组件)16——Hive:内置UDTF函数

1.4.11、内置UDTF函数1.4.11.1、explodeselect explode(array(100,200,300));Array<int> myCol[100,200,300][400,500,600]得到的结果如下&#xff1a;(int) myNewCol1002003004005006001.4.11.2、posexplodeselect posexplode(array(A,B,C));1.4.11.3、parse_url_tuples…

2023云原生安全值得关注的3个方向

如果说过去几年教会了我们什么的话&#xff0c;那就是云原生和开源环境中安全的重要性。 Log4j 等漏洞产生的重大影响&#xff0c;在无数的行业中浮现&#xff0c;对于云原生环境中的其他安全问题也越来越受到重视。 组织不再质疑是否要迁移到云端&#xff0c;而是在寻找最快、…

centos下安装docker 并通过docker安装gitlab

一:安装docker1、若之前安过docker&#xff0c;可以先卸载yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine \docker-ce2、更新yum…

软件测试基础(四) 之 软件测试的覆盖率

一、什么是软件测试的覆盖率&#xff1f;软件测试覆盖率是软件测试技术有效性的一个度量手段&#xff0c;用来度量测试完整性。意思概括的说&#xff0c;软件测试的工作中会有非常非常多的item&#xff08;任务&#xff09;&#xff0c;执行过的任务和总任务数的一个比值&#…

尚医通 (二)项目搭建

目录一、工程结构介绍1、工程结构2、模块说明二、创建父工程1、创建sprigboot工程yygh_parent2、删除 src 目录3、配置 pom.xml4、在pom.xml中添加依赖的版本三、搭建model模块1、在父工程yygh_parent下面创建模块model2、添加项目需要的依赖3、复制项目实体类和VO类四、搭建se…

require和important区别

1.require是赋值过程&#xff0c;就是把一个值赋值给另一个&#xff0c;important是对这个值的引用 2 . require 是赋值过程并且是运行时才执行&#xff0c;也就是同步加载&#xff0c;import 是解构过程并且是编译时执行&#xff0c;理解为异步加载 3.require 的性能相对于 im…

Linux部署达梦数据库超详细教程

陈老老老板&#x1f9b8;&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;国产数据库-达梦数据库&#xff08;主要讲一些达梦数据库相关的内容&#xff09;&#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下达梦数据库的下载与安装教程&#xff08;Linux版&#x…

百度网盘秒传链接生成及提取方法

百度网盘秒传链接生成及提取方法 1.认识秒传链接 首先&#xff0c;我们认识一下秒传链接的格式&#xff1a; 秒传链接是由标准提取码文件名组成。例如下面的格式&#xff1a; fd00338387f50ee5919eb3df4cfce6e3#5048587008#/影视/电影/救火奶爸.mp4 百度网盘秒传链接的提取主…

FISSURE:一款功能强大的RF和逆向工程框架

关于FISSURE FISSURE是一款功能强大的RF和逆向工程框架&#xff0c;该工具适用于不同技能水平的安全研究人员&#xff0c;并提供了信号检测、信号分类、协议发现、渗透测试、IQ操作、漏洞分析、自动化和AI/机器学习等功能。该框架旨在促进软件模块、无线电、协议、信号数据、脚…

2023年怎么开通一个抖音小店?店铺开通后做什么?开店指南!

大家好&#xff0c;我是王路飞。 2023年都已经过去一个月了&#xff0c;你开通抖音小店了吗&#xff1f; 作为目前最受欢迎的创业和副业项目&#xff0c;开通抖音小店的商家数量与日俱增&#xff0c;都是为了蹭一下抖音流量的红利&#xff0c;毕竟直播带货如今正处在风口。 …

50条必背JAVA知识点(三)

31.面向对象中两个重要的概念&#xff1a;类&#xff1a;对一类事物的描述&#xff0c;是抽象的、概念上的定义对象&#xff1a;是实际存在的该类事物的每个个体&#xff0c;因而也称为实例(instance) 32.虚拟机栈&#xff0c;即为平时提到的栈结构。局部变量存储在栈结构中&a…

专利的申请和驳回

说明书和权利要求的区别 说明书里面会写这个新方案的具体内容&#xff0c;实施方案&#xff0c;解释说明等&#xff0c;权利要求书的话&#xff0c;就是对这些具体的内容进行概括 说明书应当补充说明该发明相比有技术的优势 就投屏举例: 到底怎么写 三篇 阿里 楼x投屏方法及装…

人工智能服务哪家强?IDC评估报告看过来

如果您还不知道如何选择人工智能AI服务供应商&#xff0c;那么IDC的这份评估报告也许可以派上用场。如何选择AI软件工具和平台随着科技的不断发展&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;技术在近年来取得了长足的进步。从语音…

简介JWT

简介JWT http协议无状态的&#xff0c;所以需要sessionId或token的鉴权机制&#xff0c;jwt的token认证机制不需要在服务端再保留用户的认证信息或会话信息。这就意味着基于jwt认证机制的应用程序不需要去考虑用户在哪一台服务器登录了&#xff0c;这就为应用的扩展提供了便利&…

Python函数和 lambda表达式

Python提供了许多内置函数&#xff0c;比如&#xff1a;print()&#xff0c;len()等。它还支持用户自定义函数。 一、Python函数 1、函数定义使用 &#xff08;1&#xff09;函数定义 Python 允许我们将常用的代码以固定的格式封装&#xff08;包装&#xff09;成一个独立的…

一刷代码随想录——字符串

1 力扣344.反转字符串题目描述&#xff1a;编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。class Solution { public:v…

数据库原理与应用-关系数据库

关系数据结构及形式化定义关系操作关系的完整性关系代数关系演算

WebSocket协议简介

一、WebSocket协议是什么 WebSocket是基于TCP的应用层协议&#xff0c;用于在C/S架构的应用中实现双向通信&#xff0c;它实现了浏览器与服务器全双工(full-duplex)通信&#xff0c;也就是允许服务器主动发送信息给客户端。 WebSocket 协议主要为了解决基于 HTTP/1.x 的 Web …