vue3的单组件的编写(二)--通过对比vue2来讲解

🐯 单组件的编写(二)

主要讲了

在这里插入图片描述

🌈 响应式数据的变化

响应式数据是MVVM数据变驱动编程的特色, VUE的设计也是受 MVVM模型的启发,大部分开发者选择MVVM框架都是因为数据驱动编程比传统的事件驱动编程来的方便。而选择vue,则是方便中的方便。

⭐️ Model-View-ViewModel 简称MVVM 是一种软件架构模式,将视图UI 和 业务逻辑分开,通过逻辑数据的修改驱动视图UI的更新,因此称为 “数据驱动”,与之对应是操作DOM完成视图更新的编程方式“事件驱动”。

🚀 原理上的变化

作为最重要的一个亮点,Vue3 的响应式数据在设计上和Vue2 有很大的不同。

🐳 回顾vue2的原理

vue2 是使用了 Object.defineProperty API 的getter / setter 来实现数据的响应式,这个方法的具体用法可以参考

MDN 的文档: Object.defineProperty - MDN 。

下面使用 Object.defineProperty 实现一个简单的双向绑定 demo ,亲自敲代码试一下可以有更多的理解:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>DefineProperty Demo</title>
</head>

<body>
  <!-- 输入框和按钮 -->
  <div>
    <input type="text" id="input" />
    <button onclick="vm.text = 'Hello World'"> 设置为 hello world </button>
  </div>
  <!-- 输入框和按钮 -->

  <!-- 文本展示 -->
  <div id="output"></div>
  <!-- 文本展示 -->

  <script>
    // 声明一个响应式数据
    let vm = {};
    Object.defineProperty(vm, 'text', {
      set(value) {
        console.log("set事件触发了");
        document.querySelector("#input").value = value;
        document.querySelector("#output").innerText = value;
      }
    })

    document.querySelector("#input").oninput = function(e){
      vm.text = e.target.value;
    }

  </script>
</body>

</html>

这个小 demo 实现了这两个功能:

  1. 输入框的输入行为只修改 vm.text 的数据,但会同时更新 output 标签的文本内容
  2. 点击按钮修改 vm.text 的数据,也会触发输入框和 output 文本的更新

当然 Vue 做了非常多的工作,而非只是简单的调用了 Object.defineProperty ,可以在官网 深入 Vue 2 的响应式原理 一章了解更多 Vue 2 的响应式原理。

🐳 了解vue3的原理

vue3 是使用了 Proxy API 的getter/setter 来实现数据的响应式,这个方法的具体用法参考 MDN 的文档: Proxy - MDN 。

同样的,也来实现一个简单的双向绑定 demo ,这次使用 Proxy 来实现:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Proxy Demo</title>
  </head>
  <body>
    <!-- 输入框和按钮 -->
    <div>
      <input type="text" id="input" />
      <button onclick="vm.text = 'Hello World'">设置为 Hello World</button>
    </div>
    <!-- 输入框和按钮 -->

    <!-- 文本展示 -->
    <div id="output"></div>
    <!-- 文本展示 -->

    <script>
      // 声明一个响应式数据
      const vm = new Proxy(
        {},
        {
          set(obj,key,value){
            console.log("set事件触发了");
            document.querySelector("#input").value = value;
            document.querySelector("#output").innerText = value;
          }
        }
      )

      document.querySelector("#input").oninput = function(e){
        vm.text = e.target.value;
      }
    </script>
  </body>
</html>

这个 demo 实现的功能和使用 Object.defineProperty 的 demo 是完全一样的,也都是基于 setter 的行为完成数据更新的实现,那么为什么 Vue 3 要舍弃 Object.defineProperty ,换成 Proxy 呢?

主要原因在于 Object.defineProperty 有以下不足:

1, 无法侦听数组下标的变化, 通过 arr[i] = newValue 修改值,无法实时响应。

2,无法侦听数据长度的变化,例如通过 arr.length = 10 修改数组长度,无法实时响应。

3,只能侦听对象的属性,对于整个对象需要遍历,特别是多级对象更是要通过嵌套来深度侦听。

4,使用 Object.assign() 等方法给对象添加新属性时,也不会触发更新。

这也是为什么 Vue 2 要提供一个 Vue.set API 的原因,可以在官网 Vue 2 中检测变化的注意事项 一章了解更多说明。

而这些问题在 Proxy 都可以得到解决,可以在官网 深入 Vue 3 的响应式原理 一章了解更多这部分的内容。

🚀 用法上变化

本篇只使用 Composition API 编写组件,这是使用 Vue 3 的最大优势。

⭐️ 虽然官方文档在各个 API 的使用上都做了一定的举例,但在实际使用过程中可能会遇到一些问题,常见的情况就是有些数据用着用着就失去了响应,或者是在 TypeScript 里出现类型不匹配的报错等等。

当然,一般遇到这种情况并不一定是框架的 BUG ,而可能是使用方式不对,本章节将结合笔者最初入门 Vue 3 时遇到的问题和解决问题的心得,复盘这些响应式 API 的使用。

相对与 vue2 在 data 里面声明候,即可通过 thisl.xxx 调用响应式数据,在 vue3 的生命周期里没有了 vue 实例的 this 指向, 需要导入 ref 、reactive 等响应式API 才能声明并使用响应式数据。

// 这里导入的 `ref` 是一个响应式 API
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    // 通过响应式 API 创建的变量具备了响应性
    const msg = ref<string>('Hello World!')
  },
})

由于VUE3 新的API 很多,这里只展示常用的API,更多的请查看官方文档 响应性 API 一章查阅。

🌈响应式API之ref

ref 是最常用的一个响应式API, 它可以用来定义所有的类型的数据,包括Node 节点和组件。

没错,在 Vue 2 常用的 this.$refs.xxx 来取代 document.querySelector('.xxx') 获取 Node 节点的方式,也是使用这个 API 来取代。

🚀类型声明

在开始使用 API 之前,需要先了解在 TypeScript 中如何声明 Ref 变量的类型。

🐳API 本身的类型

先看 API 本身, ref API 是一个函数,通过接受一个泛型入参,返回一个响应式对象,所有的值都通过 .value 属性获取,这是 API 本身的 TS 类型:

// `ref` API 的 TS 类型
function ref<T>(value: T): Ref<UnwrapRef<T>>

// `ref` API 的返回值的 TS 类型
interface Ref<T> {
  value: T
}

因此在声明变量时,是使用尖括号 <> 包裹其 TS 类型,紧跟在 ref API 之后:

// 显式指定 `msg.value` 是 `string` 类型
const msg = ref<string>('Hello World!')

再回看该 API 本身的类型,其中使用了 T 泛型,这表示在传入函数的入参时,可以不需要手动指定其 TS 类型, TypeScript 会根据这个 API 所返回的响应式对象的 .value 属性的类型,确定当前变量的类型。

因此也可以省略显式的类型指定,像下面这样声明变量,其类型交给 TypeScript 去自动推导:

// TypeScript 会推导 `msg.value` 是 `string` 类型
const msg = ref('Hello World')

对于声明时会赋予初始值,并且在使用过程中不会改变其类型的变量,是可以省略类型的显式指定的。

而如果有显式的指定的类型,那么在一些特殊情况下,初始化时可以不必赋值,这样 TypeScript 会自动添加 undefined 类型:

const msg = ref<string>()
console.log(msg.value) // undefined

msg.value = 'Hello World!'
console.log(msg.value) // Hello World!

因为入参留空时,虽然指定了 string 类型,但实际上此时的值是 undefined ,因此实际上这个时候的 msg.value 是一个 string | undefined 的联合类型。

对于声明时不知道是什么值,在某种条件下才进行初始化的情况,就可以省略其初始值,但是切记在调用该变量的时候对 .value 值进行有效性判断。

而如果既不显式指定类型,也不赋予初始值,那么会被默认为 any 类型,除非真的无法确认类型,否则不建议这么做。

🐳API 返回值的类型

细心的开发者还会留意到 ref API 类型里面还标注了一个返回值的 TS 类型:

interface Ref<T> {
  value: T
}

它是代表整个 Ref 变量的完整类型:

  • 上文声明 Ref 变量时,提到的 string 类型都是指 msg.value 这个 .value 属性的类型
  • msg 这个响应式变量,其本身是 Ref<string> 类型

如果在开发过程中需要在函数里返回一个 Ref 变量,那么其 TypeScript 类型就可以这样写(请留意 Calculator 里的 num 变量的类型):

// 导入 `ref` API
import { ref } from 'vue'
// 导入 `ref` API 的返回值类型
import type { Ref } from 'vue'

// 声明 `useCalculator` 函数的返回值类型
interface Calculator {
  // 这里包含了一个 Ref 变量
  num: Ref<number>
  add: () => void
}

// 声明一个 “使用计算器” 的函数
function useCalculator(): Calculator {
  const num = ref<number>(0)

  function add() {
    num.value++
  }

  return {
    num,
    add,
  }
}

// 在执行使用计算器函数时,可以获取到一个 Ref 变量和其他方法
const { num, add } = useCalculator()
add()
console.log(num.value) // 1

上面这个简单的例子演示了如何手动指定 Ref 变量的类型,对于逻辑复用时的函数代码抽离、插件开发等场景非常有用!当然大部分情况下可以交给 TypeScript 自动推导,但掌握其用法,在必要的时候就派得上用场了!

🚀变量的定义

在了解了如何对 Ref 变量进行类型声明之后,面对不同的数据类型,相信都得心应手了!但不同类型的值之间还是有少许差异和注意事项,例如上文提及到该 API 可以用来定义所有类型的数据,包括 Node 节点和组件,具体可以参考下文的示例。

🐳基本类型

对字符串、布尔值等基本类型的定义方式,比较简单:

// 字符串
const msg = ref<string>('Hello World!')

// 数值
const count = ref<number>(1)

// 布尔值
const isVip = ref<boolean>(false)
🐳引用类型

对于对象、数组等引用类型也适用,比如要定义一个对象:

// 先声明对象的格式
interface Member {
  id: number
  name: string
}

// 在定义对象时指定该类型
const userInfo = ref<Member>({
  id: 1,
  name: 'Tom',
})

定义一个普通数组:

// 数值数组
const uids = ref<number[]>([1, 2, 3])

// 字符串数组
const names = ref<string[]>(['Tom', 'Petter', 'Andy'])

定义一个对象数组:

// 声明对象的格式
interface Member {
  id: number
  name: string
}

// 定义一个对象数组
const memberList = ref<Member[]>([
  {
    id: 1,
    name: 'Tom',
  },
  {
    id: 2,
    name: 'Petter',
  },
])

🚀DOM 元素与子组件

除了可以定义数据,ref 也有熟悉的用途,就是用来挂载节点,也可以挂在子组件上,也就是对应在 Vue 2 时常用的 this.$refs.xxx 获取 DOM 元素信息的作用。

模板部分依然是熟悉的用法,在要引用的 DOM 上添加一个 ref 属性:

<template>
  <!-- 给 DOM 元素添加 `ref` 属性 -->
  <p ref="msg">请留意该节点,有一个 ref 属性</p>

  <!-- 子组件也是同样的方式添加 -->
  <Child ref="child" />
</template>

<script /> 部分有三个最基本的注意事项:

  1. <template /> 代码里添加的 ref 属性的值,是对应 <script /> 里使用 ref API 声明的变量的名称;
  2. 请保证视图渲染完毕后再执行 DOM 或组件的相关操作(需要放到生命周期的 onMounted 或者 nextTick 函数里,这一点在 Vue 2 也是一样);
  3. 该 Ref 变量必须 return 出去才可以给到 <template /> 使用,这一点是 Vue 3 生命周期的硬性要求,子组件的数据和方法如果要给父组件操作,也要 return 出来才可以。

配合上面的 <template /> ,来看看 <script /> 部分的具体例子:

import { defineComponent, onMounted, ref } from 'vue'
import Child from '@cp/Child.vue'

export default defineComponent({
  components: {
    Child,
  },
  setup() {
    // 定义挂载节点,声明的类型详见下方附表
    const msg = ref<HTMLElement>()
    const child = ref<InstanceType<typeof Child>>()

    // 请保证视图渲染完毕后再执行节点操作 e.g. `onMounted` / `nextTick`
    onMounted(() => {
      // 比如获取 DOM 的文本
      console.log(msg.value.innerText)

      // 或者操作子组件里的数据
      child.value.isShowDialog = true
    })

    // 必须 `return` 出去才可以给到 `<template />` 使用
    return {
      msg,
      child,
    }
  },
})

关于 DOM 和子组件的 TS 类型声明,可参考以下规则:

节点类型声明类型参考文档
DOM 元素使用 HTML 元素接口HTML 元素接口
子组件使用 InstanceType 配合 typeof 获取子组件的类型typeof 操作符

TIP

单纯使用 typeof Child 虽然可以获得 Child.vue 组件的 Props 和方法等提示,但在 VSCode 的类型推导还不够智能,缺乏更有效的代码补全支持。

上文使用的 InstanceType<T> 是 TypeScript 提供的一个工具类型,可以获取构造函数类型的实例类型,因此将组件的类型声明为 InstanceType<typeof Child> ,不仅可以得到更完善的类型提示,在编程过程中还可以让编辑器提供更完善的代码补全功能。

另外,关于这一小节,有一个可能会引起 TS 编译报错的情况是,一些脚手架创建出来的项目会默认启用 --strictNullChecks 选项,会导致案例中的代码无法正常编译,出现如下报错:

npm run build

> hello-vue3@0.0.0 build
> vue-tsc --noEmit && vite build

src/views/home.vue:27:7 - error TS2532: Object is possibly 'undefined'.

27       child.value.isShowDialog = true
         ~~~~~~~~~~~


Found 1 error in src/views/home.vue:27

这是因为在默认情况下 nullundefined 是所有类型的子类型,但开启了 strictNullChecks 选项之后,会使 nullundefined 只能赋值给 void 和它们各自,这是一个更为严谨的选项,可以保障程序代码的健壮性,但对于刚接触 TypeScript 不久的开发者可能不太友好。

有以下几种解决方案可以参考:

  • 在涉及到相关操作的时候,对节点变量增加一个判断:
// 添加 `if` 分支,判断 `.value` 存在时才执行相关代码
if (child.value) {
  // 读取子组件的数据
  console.log(child.value.num)

  // 执行子组件的方法
  child.value.sayHi('Use `if` in `onMounted` API.')
}
  • 通过 TS 的可选符 ? 将目标设置为可选,避免出现错误(这个方式不能直接修改子组件数据的值):
// 读取子组件的数据(留意 `.num` 前面有一个 `?` 问号)
console.log(child.value?.num)

// 执行子组件的方法(留意 `.sayHi` 前面有一个 `?` 问号)
child.value?.sayHi('use ? in onMounted')
  • 在项目根目录下的 tsconfig.json 文件里,显式的关闭 strictNullChecks 选项,关闭后,需要开发者在写代码的时候,自行把控好是否需要对 nullundefined 进行判断:
{
  "compilerOptions": {
    // ...
    "strictNullChecks": false
  }
  // ...
}
  • 使用 any 类型代替,但是写 TypeScript 还是尽量不要使用 any ,满屏的 AnyScript 不如直接使用 JavaScript

🚀变量的读取与赋值

前面在介绍 API 类型的时候已经了解,通过 ref 声明的变量会全部变成对象,不管定义的是什么类型的值,都会转化为一个 Ref 对象,其中 Ref 对象具有指向内部值的单个 Property .value

也就是说,任何 Ref 对象的值都必须通过 xxx.value 才可以正确获取。

请牢记上面这句话,初拥 Vue 3 的开发者很多 BUG 都是由于这个问题引起的(包括笔者刚开始使用 Vue 3 的那段时间,嘿嘿)。

🐳读取变量

平时对于普通变量的值,读取的时候都是直接调用其变量名即可:

// 读取一个字符串
const msg: string = 'Hello World!'
console.log(msg)

// 读取一个数组
const uids: number[] = [1, 2, 3]
console.log(uids[1])

而 Ref 对象的值的读取,切记!必须通过 .value

// 读取一个字符串
const msg = ref<string>('Hello World!')
console.log(msg.value)

// 读取一个数组
const uids = ref<number[]>([1, 2, 3])
console.log(uids.value[1])
🐳为变量赋值

普通变量需要使用 let 声明才可以修改其值,由于 Ref 对象是个引用类型,所以可以使用 const 声明,直接通过 .value 修改。

// 声明一个字符串变量
const msg = ref<string>('Hi!')

// 等待 1s 后修改它的值
setTimeout(() => {
  msg.value = 'Hello!'
}, 1000)

因此日常业务中,像在对接服务端 API 的接口数据时,可以自由的使用 forEachmapfilter 等方法操作 Ref 数组,或者直接重置它,而不必担心数据失去响应性。

const data = ref<string[]>([])

// 提取接口的数据
data.value = api.data.map((item: any) => item.text)

// 重置数组
data.value = []

为什么突然要说这个呢?因为涉及到下一部分的知识,关于 reactive API 在使用上的注意事项。

🌈响应式API之reactive

reactive 是继 ref 之后最常用的一个响应式 API 了,相当于 ref , 它的局限性在于只适合 对象和数组

使用reactive 的好处就是写法跟平时的对象、数组几乎一模一样,但也有特殊的地方。

🚀 类型声明与定义

reactive 变量的声明方式没有 ref 的变化那么大,基本上和普通变量一样,它的 TS 类型如下:

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

可以看到其用法还是比较简单的,

🐳Reactive 对象的声明方式:
// 声明对象的类型
interface Member {
  id: number
  name: string
}

// 定义一个对象
const userInfo: Member = reactive({
  id: 1,
  name: 'Tom',
})
🐳 Reactive 数组声明
const nameList : number[] = reactive([ 1 , 2 , 3 ])
🐳 Reactive 对象数组声明
// 对象数组也是先声明其中的对象类型
interface Member {
  id: number
  name: string
}

// 再定义一个为对象数组
const userList: Member[] = reactive([
  {
    id: 1,
    name: '法外狂徒',
  },
  {
    id: 2,
    name: '张三丰',
  },
  {
    id: 3,
    name: 'come on 北鼻',
  },
])

🚀 变量的读取与赋值

虽然 reactive API 在使用上没有像 ref API 一样有 .value 的负担,但也有一些注意事项要留意。

🐳 处理对象

Reactive 对象在读取字段的值,或者修改值的时候,与普通对象是一样的,这部分没有太多问题。

// 声明对象的接口;
interface Member {
    id: number
    name: string
}

// 定义一个对象
const userInfo : Member = reactive({
    id: 1,
    name: "段誉"
})

console.log(userInfo.name)
userInfo.name = "乔峰"
🐳处理数组

Reactive数组,和普通数组会有一些区别,

普通数组 重置和修改操作:

// 定义一个普通数组
let uids : number[] = [1,2,3]

// 从另外一个对象数组里提取数据过来
uids = api.data.map((item :any) => item.id)
// 合并另外一个数组
let newUids: number[] = [4, 5, 6]
uids = [...uids, ...newUids]

// 重置数组
uids = []

Vue 2 在操作数组的时候,也可以和普通数组这样处理数据的变化,依然能够保持响应性,但在 Vue 3 ,如果使用 reactive 定义数组,则不能这么处理,必须只使用那些不会改变引用地址的操作。

笔者刚开始接触时,按照原来的思维去处理 reactive 数组,于是遇到了 “数据变了,但模板不会更新的问题” ,如果开发者在学习的过程中也遇到了类似的情况,可以从这里去入手排查问题所在。

举个例子,比如要重置数组,如果使用常规的重置,会导致这个变量失去响应性:

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

export default defineComponent({
    setup() {
        //================ reactive =====================    
        let numberList: number[] = reactive([1, 2, 3])

        function clear() {
            /**
             * 不推荐这种方式重置数组,因为会失去响应式
             * 异步添加数据到数组后,不会响应更新
             */
            numberList = [];
            console.log("numberList",numberList) //输出:numberList [] ,数据改变了,但是视图不会更新
        }

        return {
            numberList,
            clear
        }
    },
})
</script>

<template>
    <div>
        reactive 响应式数据测试
        <h3 v-for="nu in numberList">
            {{ nu }}
        </h3>
        <button @click="clear">赋值空数组重置</button>
    </div>
</template>

案例演示

在这里插入图片描述

reactive 让数据保持响应式的操作方式是:通过重置数组的 length 长度来实现数据的重置:

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

export default defineComponent({
    setup() {
        //================ reactive =====================    
        let numberList: number[] = reactive([1, 2, 3])

        function clear() {
            /**
             * 不推荐这种方式重置数组,因为会失去响应式
             * 异步添加数据到数组后,不会响应更新
             */
            numberList = [];
            console.log("numberList", numberList) //输出:numberList [] ,数据改变了,但是视图不会更新
        }

        function changeLengthclear() {
            /**
             * 推荐使用这种方式,不会破坏响应性
             */
            numberList.length = 0;
        }


        return {
            numberList,
            clear,
            changeLengthclear
        }
    },
})
</script>

<template>
    <div>
        reactive 响应式数据测试
        <h3 v-for="nu in numberList">
            {{ nu }}
        </h3>
        <button @click="clear">赋值空数组重置</button>
        <br>
        <br>
        <button @click="changeLengthclear">修改长度:数组重置</button>
    </div>
</template>

案例演示

在这里插入图片描述

🚀 特别注意

❤️ ❤️ ❤️ 不要对 Reactive 数据进行 ES6 的解构 操作,因为解构后得到的变量会失去响应性。

比如这些情况,在 2s 后都得不到新的 name 信息:

ts

import { defineComponent, reactive } from 'vue'

interface Member {
  id: number
  name: string
}

export default defineComponent({
  setup() {
    // 定义一个带有响应性的对象
    const userInfo: Member = reactive({
      id: 1,
      name: 'Petter',
    })

    // 在 2s 后更新 `userInfo`
    setTimeout(() => {
      userInfo.name = 'Tom'
    }, 2000)

    // 这个变量在 2s 后不会同步更新
    const newUserInfo: Member = { ...userInfo }

    // 这个变量在 2s 后不会再同步更新
    const { name } = userInfo

    // 这样 `return` 出去给模板用,在 2s 后也不会同步更新
    return {
      ...userInfo,
    }
  },
})

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

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

相关文章

“index“ should always be multi-word

vue报错&#xff1a;Component name “index” should always be multi-word 分析&#xff1a;组件名要以驼峰格式命名&#xff0c;自定义的要以loginIndex.vue等这种方式命名&#xff0c;防止和html标签冲突&#xff0c;所以命名index.vue 会报错 解决&#xff1a;在.eslint…

PG数据中DBeaver上传csv文件作为数据表

DBeaver 是一个开源的数据库工具&#xff0c;还是蛮好用的&#xff0c;有时候需要我们上传数据做表&#xff0c;数据为CSV格式的&#xff0c;DBeaver本身自带有功能实现的。 可打开连着的数据库&#xff0c;找到模式&#xff0c;点到下面的表里&#xff0c;选择一个表直接导入…

已完结7个,再启动1个新项目,嘎嘎强!

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 大家好&#xff0c;我是技术UP主小傅哥。 &#x1f490;又到了启动新项目的时候&#xff0c;死鬼开心嘛。小傅哥的星球&#xf…

Rust可空类型Option

文章目录 Option基础模式匹配unwrap Rust基础教程&#xff1a;初步⚙所有权⚙结构体和枚举类⚙函数进阶⚙泛型和特征⚙并发和线程通信⚙cargo包管理 Rust进阶教程&#xff1a;用宏实现参数可变的函数⚙类函数宏 Option基础 在一些编程语言中&#xff0c;允许存在空值&#xf…

Linux环境下安装部署单机RabbitMQ(离线)

摘要 本文档适用于在Linux系统下部署单体RabbitMQ&#xff0c;是在无网的情况下部署的。涉及的任何操作都是通过手动下载安装包然后上传到服务器上进行安装&#xff0c;因此也遇到一些问题&#xff0c;并在此文档中记录。 实际操作环境&#xff1a;Kylin V10&#xff0c;实际…

java疫情期间社区出入管理系统-计算机毕业设计源码21295

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对疫情期间社区出入管理等问题&#xff0c;对…

并行与分布式计算 第8章 并行计算模型

文章目录 并行与分布式计算 第8章 并行计算模型8.1 并行算法基础8.1.1 并行算法的定义8.1.2并行算法的分类8.1.3算法的复杂度 8.2 并行计算模型8.2.1 PRAM (SIMD-SM)模型8.2.3 BSP (MIMD-DM)模型8.2.4LogP&#xff08;MIMD-DM&#xff09;模型 并行与分布式计算 第8章 并行计算…

单链表OJ题——11.随机链表的复制

11.随机链表的复制 138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; /* 解题思路&#xff1a; 此题可以分三步进行&#xff1a; 1.拷贝链表的每一个节点&#xff0c;拷贝的节点先链接到被拷贝节点的后面 2.复制随机指针的链接&#xff1a;拷贝节点的随机指针指向…

单链表OJ题——10.环形链表2

10.环形链表2 142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; /* 解题思路&#xff1a; 如果链表存在环&#xff0c;则fast和slow会在环内相遇&#xff0c;定义相遇点到入口点的距离为X,定义环的长度为C,定义头到入口的距离为L,fast在slow进入环之后一圈内追上slow…

webpack环境变量的设置

现在虽然vite比较流行&#xff0c;但对于用node写后端来说&#xff0c;webpack倒是成了一个很好的打包工具&#xff0c;可以很好的保护后端的代码。所以这块的学习还是不能停下来&#xff0c;接下来我们来针对不同的环境做不同的设置写好笔记。 引用场景主要是针对服务器的各种…

小米集团收入增长失速已久:穿越寒冬,雷军的路走对了吗?

撰稿|行星 来源|贝多财经 11月20日&#xff0c;小米集团&#xff08;HK:01810&#xff0c;下称“小米”&#xff09;发布了截至2023年9月30日的第三季度业绩公告。 财报显示&#xff0c;在智能手机出货量下行、平均售价下跌的背景下&#xff0c;小米逆势而上&#xff0c;实现…

向量数据库—加速大模型训练推理

目录 前言什么是向量数据库&#xff1f;向量数据库在大模型中扮演什么角色&#xff1f;Amazon OpenSearch Serverless向量引擎使用场景 其他向量数据库FaissMilvusChromaelasticsearchTencent Cloud VectorDB 向量数据库的应用场景图像和视频处理自然语言处理推荐系统搜索引擎人…

《程序员考公指南》:零基础到上岸的完整攻略 | 开源日报 No.82

mastodon/mastodon Stars: 44.2k License: AGPL-3.0 Mastodon 是一个免费、开源的社交网络服务器&#xff0c;基于 ActivityPub。用户可以在 Mastodon 上关注朋友并发现新朋友&#xff0c;并且可以发布链接、图片、文字和视频等内容。所有的 Mastodon 服务器都能互操作成为联邦…

Open3D (C++) 计算两点云之间的最小距离

目录 一、 算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、 算法原理 Open3D中ComputePointCloudDistance函数提供了计算从源点云到目标点云的距离的方法,计算点云的距离。也…

【验证码系列】利用深度学习构建字符型验证码自动识别模型与算法

文章目录 1. 写在前面2. CSCI级设计决策2.1. 字符型验证码识别智能体流程关联2.2. 字符型验证码识别行为设计 3. 字符型验证码识别智能体结构设计3.1. 智能体部件组成3.2. 智能体结构 4. 接口设计4.1. 字符型验证码识别智能体交互 5. 智能体算法设计细节5.1. 算法目标5.2. 字符…

梳理一名Go后端程序员日常用的软件~

大家好&#xff0c;我是豆小匠。 这期分享下我日常工作用到的软件和工具&#xff01; 省流版图片↓↓↓ 工具分为四类&#xff1a;编码软件、笔记/文档软件、开发工具和日常软件等。 1. 编码软件 1.1. Goland 出自JetBrain家族&#xff0c;IDE的王者&#xff0c;作为我的…

操作系统 应用题 例题+参考答案(考研真题)

1.&#xff08;考研真题&#xff09;一个多道批处理系统中仅有P1和P2两个作业&#xff0c;P2比P1晚5ms到达&#xff0c;它们的计算和I/O操作顺序如下。 P1&#xff1a;计算60ms&#xff0c;I/O 80ms&#xff0c;计算20ms。 P2&#xff1a;计算120ms&#xff0c;I/O 40ms&…

Redis下载和安装(Windows系统)

通过 GitHub 来下载 Windows 版 Redis 安装包,下载地址&#xff1a;点击前往。 打开上述的下载链接&#xff0c;Redis 支持 32 位和 64 位的 Window 系统&#xff0c;大家根据个人情况自行下载&#xff0c;如图 1 所示&#xff1a; 下载完成后&#xff0c;打开相应的文件夹&a…

wincc定时器功能介绍

1定时器功能介绍 WinCC中定时器的使用可以使WinCC按照指定的周期或者时间点去执行任务&#xff0c;比如周期执行变量归档、在指定的时间点执行全局脚本或条件满足时打印报表。WinCC已经提供了一些简单的定时器&#xff0c;可以满足大部分定时功能。但是在有些情况下&#xff0c…

智能座舱架构与芯片 - (2) 架构篇

一、定义 1.1 智能座舱定义 按照百度百科的定义&#xff0c;智能座舱&#xff08;intelligent cabin&#xff09;旨在集成多种IT和人工智能技术&#xff0c;打造全新的车内一体化数字平台&#xff0c;为驾驶员提供智能体验&#xff0c;促进行车安全。目前国内外已经有很多研究…