当前位置: 首页 > news >正文

vue2vue3--render函数(h)

目录

h函数

方法1. 在Options API中的使用

方法2. 在Composition API中的使用 

Vue 2中的渲染函数

​基础​

vue2

vue3

vue3--声明渲染函数 

节点、树以及虚拟 DOM

​虚拟 DOM​

createElement 参数

深入数据对象

约束

vue2

vue3 

使用 JavaScript 代替模板功能

v-if 和 v-for

 vue2

vue 3

v-model 

vue2

vue3

 事件 & 按键修饰符 

vue2

vue3 

 插槽

vue2

vue3

总结

渲染函数参数

2.x 语法

3.x 语法

VNode Prop 格式化

2.x 语法

3.x 语法

注册组件

2.x 语法

3.x 语法


当谈到Vue.js的渐进式框架时,很快会想到它的核心功能之一:渲染函数。渲染函数是Vue.js的一种强大工具,允许您以编程方式创建和控制虚拟DOM。在本文中,我们将探讨Vue 2和Vue 3中的渲染函数的不同之处以及如何使用它们来构建灵活的用户界面。
 

h函数

h函数可以在两个地方使用

  • Options API 的render函数选项中;
  • setup函数选项中(setup本身需要是一个函数类型,函数再返回h函数创建的VNode)

h函数参数:

第一个参数既可以是一个字符串 (用于原生元素) 也可以是一个 Vue 组件定义。第二个参数是要传递的 prop,第三个参数是子节点。

当创建一个组件的 vnode 时,子节点必须以插槽函数进行传递。如果组件只有默认槽,可以使用单个插槽函数进行传递。否则,必须以插槽函数的对象形式来传递。

为了方便阅读,当子节点不是插槽对象时,可以省略 prop 参数。

比有如下一个template结构, 需要使用h函数创建出来

方法1. 在Options API中的使用

import { h } from "vue"export default {render() {return h("div", {className: "app"}, [h("h2", {className: "title"}, "我是标题"),h("p", null, "我是内容"),])}
}


 

  • render函数不仅可以传入普通元素, 也可以传入一个组件

import { h } from "vue"
import Home from "./home.vue"export default {render() {return h("div", { className: "app" }, [// 因为不是在模板中使用, 因此无需注册, 直接使用h(Home)])}
}

方法2. 在Composition API中的使用 

<script>
import { h } from "vue"export default {setup() {// setup是一个函数, 让这个函数再返回一个函数return () => h("div", { class: "app" }, [h("h2", { class: "title" }, "我是标题"),h("p", null, "我是内容")])}
}
</script>
  • 如果是在<script setup>标签中使用h函数, 需要如下方式(会变得很繁琐)

<template><!-- 将render函数变量写在temolate标签中 --><render></render>
</template><script setup>
import { h, ref } from "vue"const conter = ref(0)const increment = () => {conter.value ++}const decrement = () => {conter.value --}// 将这个render函数保存到一个变量中const render = () => h("div", { class: "app" }, [h("h2", { class: "title" }, `当前计数: ${conter.value}`),h("button", { onclick: increment }, "+"),h("button", { onclick: decrement }, "-")])
</script>

 

Vue 2中的渲染函数

在Vue 2中,渲染函数是一个重要的概念,但相对较复杂。它通常使用JavaScript的createElement函数来创建虚拟DOM节点。下面是一个简单的Vue 2渲染函数示例:

Vue.component('my-component', {render: function (createElement) {return createElement('div', 'Hello, Vue 2!')}
})

在这个示例中,我们创建了一个Vue组件,其中的render函数接受一个createElement参数,用于创建一个包含文本内容的<div>元素。

虽然Vue 2的渲染函数非常强大,但它的语法可能会相对复杂,并且不够直观。这使得在开发大型应用程序时,理解和维护渲染函数可能会变得困难。

​基础​


 

Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。

让我们深入一个简单的例子,这个例子里 render 函数很实用。假设我们要生成一些带锚点的标题:


vue2

<h1><a name="hello-world" href="#hello-world">Hello world!</a>
</h1>

对于2上面的 HTML,你决定这样定义组件接口:
 

<anchored-heading :level="1">Hello world!</anchored-heading>

当开始写一个只能通过 level prop 动态生成标题 (heading) 的组件时,你可能很快想到这样实现:
 

<script type="text/x-template" id="anchored-heading-template"><h1 v-if="level === 1"><slot></slot></h1><h2 v-else-if="level === 2"><slot></slot></h2><h3 v-else-if="level === 3"><slot></slot></h3><h4 v-else-if="level === 4"><slot></slot></h4><h5 v-else-if="level === 5"><slot></slot></h5><h6 v-else-if="level === 6"><slot></slot></h6>
</script>
Vue.component('anchored-heading', {template: '#anchored-heading-template',props: {level: {type: Number,required: true}}
})

这里用模板并不是最好的选择:不但代码冗长,而且在每一个级别的标题中重复书写了 <slot></slot>,在要插入锚点元素时还要再次重复。

虽然模板在大多数组件中都非常好用,但是显然在这里它就不合适了。那么,我们来尝试使用 render 函数重写上面的例子:
 

Vue.component('anchored-heading', {render: function (createElement) {return createElement('h' + this.level,   // 标签名称this.$slots.default // 子节点数组)},props: {level: {type: Number,required: true}}
})

看起来简单多了!这样代码精简很多,但是需要非常熟悉 Vue 的实例 property。在这个例子中,你需要知道,向组件中传递不带 v-slot 指令的子节点时,比如 anchored-heading 中的 Hello world!,这些子节点被存储在组件实例中的 $slots.default 中。如果你还不了解,在深入渲染函数之前推荐阅读实例 property API。

vue3

Vue 提供了一个 h() 函数用于创建 vnodes:

import { h } from 'vue'const vnode = h('div', // type{ id: 'foo', class: 'bar' }, // props[/* children */]
)

h() 是 hyperscript 的简称——意思是“能生成 HTML (超文本标记语言) 的 JavaScript”。这个名字来源于许多虚拟 DOM 实现默认形成的约定。一个更准确的名称应该是 createVnode(),但当你需要多次使用渲染函数时,一个简短的名字会更省力。

h() 函数的使用方式非常的灵活:

 

// 除了类型必填以外,其他的参数都是可选的
h('div')
h('div', { id: 'foo' })// attribute 和 property 都能在 prop 中书写
// Vue 会自动将它们分配到正确的位置
h('div', { class: 'bar', innerHTML: 'hello' })// 像 `.prop` 和 `.attr` 这样的的属性修饰符
// 可以分别通过 `.` 和 `^` 前缀来添加
h('div', { '.name': 'some-name', '^width': '100' })// 类与样式可以像在模板中一样
// 用数组或对象的形式书写
h('div', { class: [foo, { bar }], style: { color: 'red' } })// 事件监听器应以 onXxx 的形式书写
h('div', { onClick: () => {} })// children 可以是一个字符串
h('div', { id: 'foo' }, 'hello')// 没有 props 时可以省略不写
h('div', 'hello')
h('div', [h('span', 'hello')])// children 数组可以同时包含 vnodes 与字符串
h('div', ['hello', h('span', 'hello')])

得到的 vnode 为如下形式:

const vnode = h('div', { id: 'foo' }, [])vnode.type // 'div'
vnode.props // { id: 'foo' }
vnode.children // []
vnode.key // null

 

注意事项

完整的 VNode 接口包含其他内部属性,但是强烈建议避免使用这些没有在这里列举出的属性。这样能够避免因内部属性变更而导致的不兼容性问题。

vue3--声明渲染函数 

我们可以使用 render 选项来声明渲染函数:

import { h } from 'vue'export default {data() {return {msg: 'hello'}},render() {return h('div', this.msg)}
}

render() 函数可以访问同一个 this 组件实例。

除了返回一个单独的 vnode 之外,你还可以返回字符串或是数组:

export default {render() {return 'hello world!'}
}

 

import { h } from 'vue'export default {render() {// 用数组来返回多个根节点return [h('div'),h('div'),h('div')]}
}

如果一个渲染函数组件不需要任何实例状态,为了简洁起见,它们也可以直接被声明为一个函数: 

function Hello() {return 'hello world!'
}

没错,这就是一个合法的 Vue 组件!参阅函数式组件来了解更多语法细节。 

节点、树以及虚拟 DOM

在深入渲染函数之前,了解一些浏览器的工作原理是很重要的。以下面这段 HTML 为例:

 

<div><h1>My title</h1>Some text content<!-- TODO: Add tagline -->
</div>

当浏览器读到这些代码时,它会建立一个“DOM 节点”树来保持追踪所有内容,如同你会画一张家谱树来追踪家庭成员的发展一样。
上述 HTML 对应的 DOM 节点树如下图所示:

每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点 (也就是说每个部分可以包含其它的一些部分)。

高效地更新所有这些节点会是比较困难的,不过所幸你不必手动完成这个工作。你只需要告诉 Vue 你希望页面上的 HTML 是什么,这可以是在一个模板里:
 

<h1>{{ blogTitle }}</h1>

 或者一个渲染函数里:
 

render: function (createElement) {return createElement('h1', this.blogTitle)
}

在这两种情况下,Vue 都会自动保持页面的更新,即便 blogTitle 发生了改变。

​虚拟 DOM​
 

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。请仔细看这行代码:
 

return createElement('h1', this.blogTitle)

createElement 到底会返回什么呢?其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。 

createElement 参数

接下来你需要熟悉的是如何在 createElement 函数中使用模板中的那些功能。这里是 createElement 接受的参数:
 

// @returns {VNode}
createElement(// {String | Object | Function}// 一个 HTML 标签名、组件选项对象,或者// resolve 了上述任何一种的一个 async 函数。必填项。'div',// {Object}// 一个与模板中 attribute 对应的数据对象。可选。{// (详情见下一节)},// {String | Array}// 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,// 也可以使用字符串来生成“文本虚拟节点”。可选。['先写一些文字',createElement('h1', '一则头条'),createElement(MyComponent, {props: {someProp: 'foobar'}})]
)

深入数据对象
 

有一点要注意:正如 v-bind:class 和 v-bind:style 在模板语法中会被特别对待一样,它们在 VNode 数据对象中也有对应的顶层字段。该对象也允许你绑定普通的 HTML attribute,也允许绑定如 innerHTML 这样的 DOM property (这会覆盖 v-html 指令)。
 

{// 与 `v-bind:class` 的 API 相同,// 接受一个字符串、对象或字符串和对象组成的数组'class': {foo: true,bar: false},// 与 `v-bind:style` 的 API 相同,// 接受一个字符串、对象,或对象组成的数组style: {color: 'red',fontSize: '14px'},// 普通的 HTML attributeattrs: {id: 'foo'},// 组件 propprops: {myProp: 'bar'},// DOM propertydomProps: {innerHTML: 'baz'},// 事件监听器在 `on` 内,// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。// 需要在处理函数中手动检查 keyCode。on: {click: this.clickHandler},// 仅用于组件,用于监听原生事件,而不是组件内部使用// `vm.$emit` 触发的事件。nativeOn: {click: this.nativeClickHandler},// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`// 赋值,因为 Vue 已经自动为你进行了同步。directives: [{name: 'my-custom-directive',value: '2',expression: '1 + 1',arg: 'foo',modifiers: {bar: true}}],// 作用域插槽的格式为// { name: props => VNode | Array<VNode> }scopedSlots: {default: props => createElement('span', props.text)},// 如果组件是其它组件的子组件,需为插槽指定名称slot: 'name-of-slot',// 其它特殊顶层 propertykey: 'myKey',ref: 'myRef',// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,// 那么 `$refs.myRef` 会变成一个数组。refInFor: true
}

约束
 

VNode 必须唯一

组件树中的所有 VNode 必须是唯一的。这意味着,下面的渲染函数是不合法的:

vue2

render: function (createElement) {var myParagraphVNode = createElement('p', 'hi')return createElement('div', [// 错误 - 重复的 VNodemyParagraphVNode, myParagraphVNode])
}

如果你真的需要重复很多次的元素/组件,你可以使用工厂函数来实现。例如,下面这渲染函数用完全合法的方式渲染了 20 个相同的段落:
 

render: function (createElement) {return createElement('div',Array.apply(null, { length: 20 }).map(function () {return createElement('p', 'hi')}))
}

vue3 

组件树中的 vnodes 必须是唯一的。下面是错误示范:

function render() {const p = h('p', 'hi')return h('div', [// 啊哦,重复的 vnodes 是无效的p,p])
}

如果你真的非常想在页面上渲染多个重复的元素或者组件,你可以使用一个工厂函数来做这件事。比如下面的这个渲染函数就可以完美渲染出 20 个相同的段落:

function render() {return h('div',Array.from({ length: 20 }).map(() => {return h('p', 'hi')}))
}

 

使用 JavaScript 代替模板功能

v-if 和 v-for

 vue2

只要在原生的 JavaScript 中可以轻松完成的操作,Vue 的渲染函数就不会提供专有的替代方法。比如,在模板中使用的 v-if 和 v-for

<ul v-if="items.length"><li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>

这些都可以在渲染函数中用 JavaScript 的 if/else 和 map 来重写

props: ['items'],
render: function (createElement) {if (this.items.length) {return createElement('ul', this.items.map(function (item) {return createElement('li', item.name)}))} else {return createElement('p', 'No items found.')}
}

vue 3

v-if

<div><div v-if="ok">yes</div><span v-else>no</span>
</div>

等价于使用如下渲染函数 

h('div', [this.ok ? h('div', 'yes') : h('span', 'no')])

v-for 

<ul><li v-for="{ id, text } in items" :key="id">{{ text }}</li>
</ul>

等价于使用如下渲染函数  

h('ul',this.items.map(({ id, text }) => {return h('li', { key: id }, text)})
)

 

v-model 

vue2

渲染函数中没有与 v-model 的直接对应——你必须自己实现相应的逻辑:

props: ['value'],
render: function (createElement) {var self = thisreturn createElement('input', {domProps: {value: self.value},on: {input: function (event) {self.$emit('input', event.target.value)}}})
}

这就是深入底层的代价,但与 v-model 相比,这可以让你更好地控制交互细节。

vue3

v-model 指令扩展为 modelValue 和 onUpdate:modelValue 在模板编译过程中,我们必须自己提供这些 props:

export default {props: ['modelValue'],emits: ['update:modelValue'],render() {return h(SomeComponent, {modelValue: this.modelValue,'onUpdate:modelValue': (value) => this.$emit('update:modelValue', value)})}
}

 事件 & 按键修饰符 

vue2

对于 .passive.capture 和 .once 这些事件修饰符,Vue 提供了相应的前缀可以用于 on

on: {'!click': this.doThisInCapturingMode,'~keyup': this.doThisOnce,'~!mouseover': this.doThisOnceInCapturingMode
}

对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:

这里是一个使用所有修饰符的例子: 

on: {keyup: function (event) {// 如果触发事件的元素不是事件绑定的元素// 则返回if (event.target !== event.currentTarget) return// 如果按下去的不是 enter 键或者// 没有同时按下 shift 键// 则返回if (!event.shiftKey || event.keyCode !== 13) return// 阻止 事件冒泡event.stopPropagation()// 阻止该元素默认的 keyup 事件event.preventDefault()// ...}
}

vue3 

对于 .passive.capture 和 .once 事件修饰符,可以使用驼峰写法将他们拼接在事件名后面:

实例:

h('input', {onClickCapture() {/* 捕捉模式中的监听器 */},onKeyupOnce() {/* 只触发一次 */},onMouseoverOnceCapture() {/* 单次 + 捕捉 */}
})
<inputonClickCapture={() => {}}onKeyupOnce={() => {}}onMouseoverOnceCapture={() => {}}
/>

 对于事件和按键修饰符,可以使用 withModifiers 函数:

import { withModifiers } from 'vue'h('div', {onClick: withModifiers(() => {}, ['self'])
})
<div onClick={withModifiers(() => {}, ['self'])} />

 

 插槽

vue2

你可以通过 this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组:

render: function (createElement) {// `<div><slot></slot></div>`return createElement('div', this.$slots.default)
}

也可以通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数:

props: ['message'],
render: function (createElement) {// `<div><slot :text="message"></slot></div>`return createElement('div', [this.$scopedSlots.default({text: this.message})])
}

如果要用渲染函数向子组件中传递作用域插槽,可以利用 VNode 数据对象中的 scopedSlots 字段:

render: function (createElement) {// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`return createElement('div', [createElement('child', {// 在数据对象中传递 `scopedSlots`// 格式为 { name: props => VNode | Array<VNode> }scopedSlots: {default: function (props) {return createElement('span', props.text)}}})])
}

vue3

在渲染函数中,可以通过 this.$slots 来访问插槽:

export default {props: ['message'],render() {return [// <div><slot /></div>h('div', this.$slots.default()),// <div><slot name="footer" :text="message" /></div>h('div',this.$slots.footer({text: this.message}))]}
}

传递插槽

向组件传递子元素的方式与向元素传递子元素的方式有些许不同。我们需要传递一个插槽函数或者是一个包含插槽函数的对象而非是数组,插槽函数的返回值同一个正常的渲染函数的返回值一样——并且在子组件中被访问时总是会被转化为一个 vnodes 数组。

h(MyComponent, () => 'hello')// 具名插槽
// 注意 `null` 是必需的
// 以避免 slot 对象被当成 prop 处理
h(MyComponent, null, {default: () => 'default slot',foo: () => h('div', 'foo'),bar: () => [h('span', 'one'), h('span', 'two')]
})

插槽以函数的形式传递使得它们可以被子组件懒调用。这能确保它被注册为子组件的依赖关系,而不是父组件。这使得更新更加准确及有效。

总结

此更改不会影响 <template> 用户。

以下是更改的简要总结:

  • h 现在是全局导入,而不是作为参数传递给渲染函数
  • 更改渲染函数参数,使其在有状态组件和函数组件的表现更加一致
  • VNode 现在有一个扁平的 prop 结构

请继续阅读来获取更多信息!

渲染函数参数

2.x 语法

在 2.x 中,render 函数会自动接收 h 函数 (它是 createElement 的惯用别名) 作为参数:

// Vue 2 渲染函数示例
export default {render(h) {return h('div')}
}

3.x 语法

在 3.x 中,h 函数现在是全局导入的,而不是作为参数自动传递。

// Vue 3 渲染函数示例
import { h } from 'vue'export default {render() {return h('div')}
}

VNode Prop 格式化

2.x 语法

在 2.x 中,domProps 包含 VNode prop 中的嵌套列表:

// 2.x
{staticClass: 'button',class: { 'is-outlined': isOutlined },staticStyle: { color: '#34495E' },style: { backgroundColor: buttonColor },attrs: { id: 'submit' },domProps: { innerHTML: '' },on: { click: submitForm },key: 'submit-button'
}

3.x 语法

在 3.x 中,整个 VNode prop 的结构都是扁平的。使用上面的例子,来看看它现在的样子。

// 3.x 语法
{class: ['button', { 'is-outlined': isOutlined }],style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],id: 'submit',innerHTML: '',onClick: submitForm,key: 'submit-button'
}

注册组件

2.x 语法

在 2.x 中,注册一个组件后,把组件名作为字符串传递给渲染函数的第一个参数,它可以正常地工作:

// 2.x
Vue.component('button-counter', {data() {return {count: 0}},template: `<button @click="count++">Clicked {{ count }} times.</button>`
})export default {render(h) {return h('button-counter')}
}

3.x 语法

在 3.x 中,由于 VNode 是上下文无关的,不能再用字符串 ID 隐式查找已注册组件。取而代之的是,需要使用一个导入的 resolveComponent 方法:

// 3.x
import { h, resolveComponent } from 'vue'export default {setup() {const ButtonCounter = resolveComponent('button-counter')return () => h(ButtonCounter)}
}

相关文章:

vue2vue3--render函数(h)

目录 h函数 方法1. 在Options API中的使用 方法2. 在Composition API中的使用 Vue 2中的渲染函数 ​基础​ vue2 vue3 vue3--声明渲染函数 节点、树以及虚拟 DOM ​虚拟 DOM​ createElement 参数 深入数据对象 约束 vue2 vue3 使用 JavaScript 代替模板功能…...

网络协议--动态选路协议

10.1 引言 在前面各章中&#xff0c;我们讨论了静态选路。在配置接口时&#xff0c;以默认方式生成路由表项&#xff08;对于直接连接的接口&#xff09;&#xff0c;并通过route命令增加表项&#xff08;通常从系统自引导程序文件&#xff09;&#xff0c;或是通过ICMP重定向…...

30天精通Nodejs--第一天:入门指南

介绍 看一下下面这段比较官方的介绍: Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,可以用于构建可扩展的网络应用程序。它的特点在于能够使JavaScript在服务器端运行,能够利用JavaScript的强大功能来处理服务器端的事务。 Nodejs的特点 高效的异步编程:Node.…...

C# ref用法,实现引用传递(地址传递)

前言&#xff1a; 今天这篇文章我们简单学习一下C# ref的用法&#xff0c;在看别人的代码不至于看不懂逻辑&#xff0c;虽然这是一个比较简单的知识点&#xff0c;但是还是值得我们去学习一下关于这个知识点一些概念&#xff0c;我们知道在C# 中我们的函数参数&#xff0c;一般…...

微信小程序数据交互------WXS的使用

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.数据库连接 数据表结构&#xff1a; 数据测式&#xff1a; 2.后台配置 pom.xml <?xml version&quo…...

【数据结构】String类对象的创建与字符串常量池的“神秘交易”

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVA数据结构》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力…...

搞个微信小程序002:个人信息

新建一个用于&#xff0c;和001中一样&#xff0c;然后&#xff0c;就改掉两个文件&#xff1a; index.wxml: <view><!-- 头像区域 --><view class"top"><view class"user-img"><image src"/images/tx.png"><…...

.obj模型文件(带材质和纹理)合并的基本思路

1、将v开头的顶点信息依次拷贝到合并新.obj中 2、将vt纹理坐标依次拷贝到合并新.obj中 3、f&#xff08;面&#xff09;的合并 步骤&#xff1a; &#xff08;1&#xff09;第一个obj文件的f&#xff08;面&#xff09;原封不动拷进新.obj中 &#xff08;2&#xff09;第二个…...

es : java 查询

1. POM 配置 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.6.2</version></dependency> 2. 建立ES集群连接 RestHighLevelClient cli…...

MySQL MVCC机制探秘:数据一致性与并发处理的完美结合,助你成为数据库高手

一、前言 在分析 MVCC 的原理之前&#xff0c;我们先回顾一下 MySQL 的一些内容以及关于 MVCC 的一些简单介绍。&#xff08;注:下面没有特别说明默认 MySQL 的引擎为 InnoDB &#xff09; 1.1 数据库的并发场景 数据库并发场景有三种&#xff0c;分别是&#xff1a; 读-读…...

5分钟搞懂分布式可观测性

可观测性是大规模分布式(微服务)系统的必要组件&#xff0c;没有可观测系统的支持&#xff0c;监控和调试分布式系统将是一场灾难。本文讨论了可观测系统的主要功能&#xff0c;并基于流行的开源工具搭建了一套可观测系统架构。原文: A Primer on Distributed Systems Observab…...

桥梁结构健康监测系统落地方案

桥梁结构健康监测的意义是多方面的。首先&#xff0c;它可以实时采集桥梁的结构数据&#xff0c;并对其进行处理和分析&#xff0c;以确定结构损伤的位置、评估桥梁的健康状况&#xff0c;并预测承载力的发展趋势。这有助于及时发现桥梁的结构问题和潜在风险&#xff0c;为采取…...

hive和presto的求数组长度函数区别及注意事项

1、任务 获取邮箱字符串’后字符串 &#xff0c;求长度 2、hive & spark-sql 求数组长度的函数 size hive & spark-sql 求数组长度的函数 sizeselect size(split(email, )),split(email, ),split(email, )[0],split(email, )[1] FROM (select "jack126.com"…...

Kotlin Lambda表达式与标准库中的高阶函数

在Kotlin中&#xff0c;Lambda表达式和标准库中的高阶函数为我们提供了一种简洁而强大的方式来处理集合和执行各种操作。本篇博客将介绍Lambda表达式的基本概念&#xff0c;并结合标准库中的高阶函数示例&#xff0c;展示它们的用法和功能。 Lambda表达式的基本概念 Lambda表…...

【JavaEE初阶】 CAS详解

文章目录 &#x1f332;什么是 CAS&#x1f6a9;CAS伪代码 &#x1f38b;CAS 是怎么实现的&#x1f333;CAS的应用&#x1f6a9;实现原子类&#x1f6a9;实现自旋锁 &#x1f384;CAS 的 ABA 问题&#x1f6a9;什么是 ABA 问题&#x1f6a9;ABA 问题引来的 BUG&#x1f6a9;解决…...

Docker镜像制作

目录 Dockfile是什么 构建镜像的三个步骤 dockerfile内容基础知识 docker执行一个Dockerfile脚本的大致流程 Dockerfile指令 FROM MAINTAINER RUN EXPOSE WORKDIR ENV ADD COPY VOLUME USER ONBUILD CMD ENTRYPOINT CMD和ENTRYPOINT区别 构建dockerfile Do…...

v-on 可以监听多个方法吗?

目录 ​编辑 前言&#xff1a;Vue 3 中的 v-on 指令 详解&#xff1a;v-on 指令的基本概念 用法&#xff1a;v-on 指令监听多个方法 解析&#xff1a;v-on 指令的优势和局限性 优势 局限性 **v-on 指令的最佳实践** - **适度监听**&#xff1a; - **方法抽离**&#x…...

【Docker】Docker Compose的使用

我们知道使用一个Dockerfile模板文件&#xff0c;可以让用户很方便的定义⼀个单独的应用容器。然而&#xff0c;在日常工作中&#xff0c;经常会碰到需要多个容器相互配合来完成某项任务的情况。 例如要实现一个Web项目&#xff0c;除了Web服务容器本身&#xff0c;往往还需要…...

2023年中国调速器产量、销量及市场规模分析[图]

调速器行业是指生产、销售和维修各种调速器设备的行业。调速器是一种能够改变机械传动系统输出转速的装置&#xff0c;通过调整输入和输出的转速比来实现转速调节的功能。 调速器行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 随着工业自动化程度…...

深入了解JVM调优:解锁Java应用程序性能的秘诀

文章目录 &#x1f34a; JVM调优&#x1f389; 增大Eden 空间大小&#x1f389; 如果MinorGC 频繁&#xff0c;且容易引发 Full GC&#x1f4dd; S1 区大小 < MGC 存活的对象大小&#xff0c;对象的年龄才1岁&#x1f4dd; 相同年龄的对象所占总空间大小>s1区空间大小的一…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程

基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)

漏洞概述 漏洞名称&#xff1a;Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号&#xff1a;CVE-2023-25194 CVSS评分&#xff1a;8.8 影响版本&#xff1a;Apache Kafka 2.3.0 - 3.3.2 修复版本&#xff1a;≥ 3.4.0 漏洞类型&#xff1a;反序列化导致的远程代…...

OpenHarmony标准系统-HDF框架之I2C驱动开发

文章目录 引言I2C基础知识概念和特性协议&#xff0c;四种信号组合 I2C调试手段硬件软件 HDF框架下的I2C设备驱动案例描述驱动Dispatch驱动读写 总结 引言 I2C基础知识 概念和特性 集成电路总线&#xff0c;由串网12C(1C、12C、Inter-Integrated Circuit BUS)行数据线SDA和串…...

vue3 手动封装城市三级联动

要做的功能 示意图是这样的&#xff0c;因为后端给的数据结构 不足以使用ant-design组件 的联动查询组件 所以只能自己分装 组件 当然 这个数据后端给的不一样的情况下 可能组件内对应的 逻辑方式就不一样 毕竟是 三个 数组 省份 城市 区域 我直接粘贴组件代码了 <temp…...

SDU棋界精灵——硬件程序ESP32实现opus编码

一、 ​​音频处理框架​ 该项目基于Espressif的音频处理框架构建,核心组件包括 ESP-ADF 和 ESP-SR,以下是完整的音频处理框架实现细节: 1.核心组件 (1) 音频前端处理 (AFE - Audio Front-End) ​​main/components/audio_pipeline/afe_processor.c​​功能​​: 声学回声…...