vue源码解析——vue如何将template转换为render函数

news2024/11/23 23:57:09

Vue 将模板(template)转换为渲染函数(render function)是 Vue 编译器的核心功能,它是 Vue 实现响应式和虚拟 DOM 的关键步骤。在 Vue 中,模板(template)是开发者编写的类似 HTML 的代码,用于描述页面的结构和交互逻辑。渲染函数(render function)是 Vue 编译器将模板转换为JavaScript 函数,用于生成虚拟 DOM,并最终渲染到页面上。所以render的作用是生成虚拟dom。你可能会想,为什么vue要写template而不是html?为什么写了template通过render将模板生成虚拟dom,而不是直接生成html呢?请往下看

 vue模板渲染是个很复杂的过程,牵扯vue的响应式和虚拟dom。本文只抓核心流程,不关心具体实现。纵向深入,不做横向扩展,避免罗里吧嗦又抓不住重点。

vue中的template模板

在Vue中,模板(template)指的是开发者编写的类似HTML的代码,用于描述页面的结构、样式和交互逻辑。模板中可以包含Vue特有的指令、数据绑定、事件处理等内容,通过Vue的编译器将模板转换为渲染函数,最终渲染到页面上。

vue2的template

以下是一个简单的Vue2模板示例:比较简单的Vue模板,描述了页面的结构和交互逻辑,通过Vue的数据绑定和事件处理机制实现了动态更新页面内容的功能

<template>
  <div>
    <h1>{{ message }}</h1>
    <p>计数:{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!',
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    }
  }
};
</script>

<style>
h1 {
  color: blue;
}
p {
  font-size: 16px;
}
button {
  background-color: green;
  color: white;
  padding: 5px 10px;
  cursor: pointer;
}
</style>

在上面的示例中,<template> 标签内包含了页面的结构,包括一个标题、一个段落和一个按钮。模板中使用了双大括号语法 {{ }} 进行数据绑定,将 message 和 count 的值动态显示在页面上。按钮上使用了 @click 指令绑定了 increment 方法,实现点击按钮增加计数的功能。

vue3的template

以下是一个简单的Vue3模板示例:使用 <script setup> 语法的Vue 3模板,通过更简洁的语法实现了相同的功能。

<template>
  <div>
    <h1>{{ message }}</h1>
    <p>计数:{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const message = ref('Hello, Vue 3!');
const count = ref(0);

const increment = () => {
  count.value++;
};
</script>

<style>
h1 {
  color: blue;
}
p {
  font-size: 16px;
}
button {
  background-color: green;
  color: white;
  padding: 5px 10px;
  cursor: pointer;
}
</style>

在这个示例中,我们使用 <script setup> 语法来定义组件的逻辑部分。通过 import { ref } from 'vue'; 引入 ref 函数,然后直接在 <script setup> 中定义 message 和 count 两个响应式数据,以及 increment 方法。这样可以更加简洁地管理组件的状态和逻辑。

 思考:为什么vue写成template形式而不是html

Vue.js 使用 template 而不是直接使用 HTML主要考虑了以下几个原因:

  1. 数据绑定:Vue.js 使用了数据绑定技术,可以动态地渲染和更新视图。如果直接使用 HTML,则需要使用一些特殊的语法来实现数据绑定,这会使 HTML 变得复杂和难以维护。
  2. 组件化:Vue.js 是一个基于组件的框架,可以将复杂的应用分解成多个小的组件。如果直接使用 HTML,则无法实现组件化的特性,因为 HTML 本身不支持组件的概念。
  3. 虚拟 DOM:Vue.js 使用了虚拟 DOM 技术,可以更高效地渲染和更新视图。如果直接使用 HTML,则需要使用一些特殊的语法来实现虚拟 DOM,这会使 HTML 变得复杂和难以维护。
  4. 编译优化:Vue.js 在编译期间可以对 template 进行优化,例如将相同的元素合并成一个元素,提高渲染性能。如果直接使用 HTML,则无法进行这种优化。

因此,Vue.js 使用 template 可以更好地支持数据绑定、组件化、虚拟 DOM 和编译优化等特性,同时可以让我们使用简单直观的方式来定义组件的结构和内容。

为什么render不直接将template转成html,而是转成了虚拟dom?

当我们使用 Vue ,往往会将页面拆分为各种组件,通过拼装组件来形成页面和应用,就像搭积木一样。模板编译后组件所产出的内容并不是 html 字符串,而是大家所熟知的 Virtual DOM。

 

组件最核心的东西是 render 函数,剩余的其他内容,如 datacompoutedprops 等都是为 render 函数提供数据来源服务的。render 函数本可以直接产出 html 字符串,但却产出了 Virtual DOMVirtual DOM 终究要渲染真实 DOM,这个过程就可以理解为模板引擎年代的完全替换 html,只不过它采用的不是完全替换,我们通常把这个过程叫做 patch。当数据变更时,组件会产出新的 VNode,我们只需再次调用 patch 函数即可

 为何组件要从直接产出 html 变成产出 Virtual DOM 呢?

其原因是 Virtual DOM 带来了 分层设计,它对渲染过程的抽象,使得框架可以渲染到 web(浏览器) 以外的平台,以及能够实现 SSR 等。至于 Virtual DOM 相比原生 DOM 操作的性能,这并非 Virtual DOM 的目标,确切地说,如果要比较二者的性能是要“控制变量”的,例如:页面的大小、数据变化量等

组件从直接产出 HTML 变成产出 Virtual DOM 的主要原因包括以下几点:

  1. 性能优化:Virtual DOM 可以作为一个轻量级的内存数据结构存在于内存中,通过对 Virtual DOM 进行比对,可以最小化对实际 DOM 的操作,从而提高性能。相比直接操作实际 DOM,Virtual DOM 的比对操作更高效,可以减少不必要的 DOM 操作,提升页面渲染性能。

  2. 跨平台兼容:Virtual DOM 的抽象层可以使得组件的渲染逻辑与具体平台无关,从而实现跨平台兼容。通过 Virtual DOM,可以将组件的渲染逻辑统一抽象,使得组件可以在不同平台上进行渲染,提高了组件的复用性和可移植性。

  3. 方便的状态管理:Virtual DOM 可以轻松地与状态管理库(如 Vuex、Redux 等)结合使用,实现组件状态的管理和更新。通过 Virtual DOM,可以更方便地管理组件的状态变化,实现数据驱动的视图更新。

  4. 简化复杂的 DOM 操作:直接操作实际 DOM 可能会涉及复杂的 DOM 操作,而 Virtual DOM 可以将这些操作抽象成简单的数据结构,使得组件的开发和维护更加简单和高效。

  5. 提高开发效率:通过 Virtual DOM,开发者可以更加专注于组件的逻辑和交互,而不需要过多关注底层的 DOM 操作细节。这样可以提高开发效率,减少开发成本。

综上所述,组件从直接产出 HTML 变成产出 Virtual DOM 主要是为了提高性能、跨平台兼容、方便的状态管理、简化复杂的 DOM 操作以及提高开发效率等方面的考虑。通过 Virtual DOM,可以更好地实现组件化开发和优化页面性能,提升用户体验。

编译VS运行时render

在大多数情况下,Vue会在编译阶段将模板(template)转换为渲染函数。这意味着Vue的编译器会在构建时将模板解析成渲染函数的静态代码,然后将这些静态代码打包到最终的构建文件中。编译时生成的渲染函数可以提高性能,因为它们是预先生成的静态代码,不需要在运行时进行解析和编译。

部分render函数在运行时生成

  • 在某些情况下,特别是在使用Vue的单文件组件(.vue文件)时,渲染函数可能会在运行时动态生成。这种情况下,Vue会在运行时解析模板并生成渲染函数。
  • 在运行时动态生成渲染函数的过程中,Vue会利用编译器将模板转换为可执行的JavaScript代码,以便在每次组件渲染时动态生成虚拟DOM。这种方式相对于编译时生成静态渲染函数会带来一些性能开销,因为需要在每次渲染时进行模板解析和代码生成。

注:使用npm run dev,开发模式下虽然不会生成最终的生产构建文件,但是在使用 npm run dev 启动开发服务器时,Vue 项目中的代码仍然会经历编译和预处理过程,以便在开发服务器上实时编译和加载。

  vue2的模板编译

实现模板编译共有三个阶段:解析、优化和生成

在vue2中,通过重写$mount方法,使得在调用原始的 $mount 函数之前,从 template 选项中获取模板字符串或 DOM 元素,并将其编译为 render 函数和 staticRenderFns 数组。确保当前实例在调用 $mount 函数时已经具有 render 函数,从而可以正确地渲染到页面上。编译时生成的 render 函数会被挂载到组件实例的 $options 对象上的 render 属性中。这样,在组件实例化时,Vue 就可以直接从 $options.render 中获取到预先编译好的 render 函数,而不需要每次都重新编译。 

 过程具体如下:

首先,Vue的编译器会将Vue模板(template)字符串解析为抽象语法树(Abstract Syntax Tree,AST)。AST表示了模板的结构和内容。编译器会对AST进行静态分析,识别模板中的静态内容(不会改变的部分)和动态内容(会改变的部分)。在静态分析的基础上,编译器会进行一些优化操作,例如静态节点提升(Static Node Hoisting)和静态属性提升(Static Props Hoisting),以减少渲染时的开销。根据AST和优化后的结果,编译器会生成对应的渲染函数代码。静态内容会被转换为静态的JavaScript代码,而动态内容会被转换为动态的JavaScript表达式。最终生成的渲染函数代码会被包含在最终的构建文件中,用于在组件渲染时生成虚拟DOM并更新页面。

render伪代码

重写$mount方法

const mount = Vue.prototype.$mount;//记录原$mount
Vue.prototype.$mount = function (el) {
  const vm = this;
  const options = vm.$options;
  el = document.querySelector(el);

  // 如果没有render方法
  if (!options.render) {
    let template = options.template;
    // 如果没有模板但是有el
    if (!template && el) {
      template = el.outerHTML;
    }
    const render = compileToFunctions(template);
    // 将render函数挂载到options上。
    options.render = render;
  }
  mount.call(this,..)//调用原$mount方法
}

Vue.prototype._init = function (options) {
  const vm = this;
  vm.$options = options;
  // 初始化状态
  initState(vm);
  // 页面挂载
  if (vm.$options.el) {
    vm.$mount(vm.$options.el);
  }
}

compileToFunctions

export function compileToFunctions(template) {
  const root = parseHTML(template);
  let code = generate(root);
  let render = `with(this){return ${code}}`;
  let renderFn = new Function(render);
  return renderFn
}

vue2源码实现

 重写$mount方法

 首先,重写的$mount函数会检查 el 参数是否为字符串或 DOM 元素,如果不是,则会将其转换为字符串或 DOM 元素。如果 el 参数为 document.bodydocument.documentElement,则会打印一个警告信息,并返回当前实例。

接下来,这个$mount函数会检查当前实例的 $options 对象是否包含 render 函数,如果不包含,则会尝试从 template 选项中获取模板字符串或 DOM 元素,并将其编译为 render 函数。如果 template 选项为字符串,则会将其转换为模板字符串或 ID 选择器,并查找对应的 DOM 元素。如果 template 选项为 DOM 元素,则会获取其 innerHTML 属性。如果 template 选项不存在,则会尝试从 el 参数获取模板字符串或 DOM 元素。

如果 template 选项为字符串或 DOM 元素,则会使用 compileToFunctions 函数将其编译为 render 函数和 staticRenderFns 数组。并且render 函数和 staticRenderFns 数组挂载到当前实例的 $options 对象上

compileToFunctions 函数是 Vue.js 中的编译器函数,它可以将模板字符串或 DOM 元素编译为 render 函数和 staticRenderFns 数组,并将其返回。

最后,这个函数会调用原始的 $mount 函数,并将 elhydrating 参数传递给它。

compileToFunctions方法

compileToFunctions 函数,它是将模板编译为 render 函数的入口函数。在这个函数中,Vue 的编译器会将模板解析成抽象语法树(AST),然后根据 AST 生成对应的 render 函数。

 通过render函数反向去找怎么生成的

在 Vue.js 的源码中,createCompiler 函数是用于创建一个新的编译器的函数。createCompiler 函数调用createCompilerCreator函数,接收一个名为 baseCompile 的函数作为参数,并返回一个新的编译器函数。

当调用 createCompilerCreator函数时,会返回一个新的编译器函数,该函数包含 compilecompileToFunctions 两个方法

compile 方法用于编译模板,并返回一个包含渲染函数和抽象语法树(AST)的对象。渲染函数是一个可以直接在渲染过程中使用的函数,而 AST 是模板的抽象语法树,可以用于进一步优化和代码生成。

compileToFunctions 方法也用于编译模板,但返回的是一个包含渲染函数和静态渲染函数数组的对象。这个方法可以用于将模板编译为可以直接在浏览器中运行的 JavaScript 函数。

baseCompile函数

baseCompile 是一个函数,在 createCompiler 函数中被用作参数,返回一个新的编译器函数。baseCompile 函数的作用是将模板编译为抽象语法树(AST)并对其进行优化和代码生成。具体来说,编译器会遍历模板的 AST,根据不同的节点类型生成相应的代码片段,最终拼接成一个完整的 render 函数。这个 render 函数会在组件实例化时被调用,用于生成虚拟 DOM。

baseCompile 函数接收两个参数:

  1. template:要编译的模板字符串。
  2. options:编译选项。

baseCompile 函数首先调用 parse 函数将模板解析为 AST,然后对 AST 进行优化,最后调用 generate 函数生成渲染函数和静态渲染函数数组。

parse 函数中,模板被解析为一个包含元素、指令和表达式的 AST。在 optimize 函数中,对 AST 进行优化以提高渲染性能。在 generate 函数中,根据 AST 生成渲染函数和静态渲染函数数组。

每个阶段具体如下:

 1.模板解析-ast语法树

首先,Vue的编译器会将Vue模板(template)字符串解析为抽象语法树(Abstract Syntax Tree,AST)。AST表示了模板的结构和内容。

解析html的parse代码很长,几百行,它的作用就是将模板转换为ast语法树。给个示例看下ast语法树的样子吧

在AST explorer这个网站,可以看vue的模板转换为ast语法树的效果

AST (Abstract Syntax Tree),抽象语法树,记录了源代码的结构和语法信息。具体来说,AST 记录了以下信息:

  1. 节点类型:每个节点都有一个类型,例如表达式、函数、变量声明等。
  2. 节点内容:每个节点都有具体的内容,例如表达式的值、函数的名称和参数等。
  3. 子节点:每个节点可能有多个子节点,例如函数可能有多个参数,表达式可能有多个操作数。
  4. 位置信息:每个节点都有位置信息,包括行号和列号,用于定位源代码中的位置。

在 Vue.js 中,AST 记录了模板的结构和语法信息,包括以下内容:

  1. 元素:每个AST节点对应一个模板中的元素,包括标签、文本和注释。
  2. 属性:每个元素可能有多个属性,包括普通属性和指令属性。
  3. 表达式:元素和属性可能包含表达式,例如 v-if 指令中的表达式。
  4. 位置信息:每个AST节点都有位置信息,包括行号和列号,用于定位模板中的位置。

通过记录这些信息,可以更好地理解和分析模板,并进行优化和代码生成,以提高渲染性能。

2.静态分析

编译器会对AST进行静态分析,识别模板中的静态内容(不会改变的部分)和动态内容(会改变的部分)。

  

3.优化

在静态分析的基础上,编译器会进行一些优化操作,例如静态节点提升(Static Node Hoisting)和静态属性提升(Static Props Hoisting)。优化器的作用是在AST中找出静态子树并打上标记。静态子树是在AST中永远不变的节点,如纯文本节 点,以减少渲染时的开销。

标记静态子树的好处:

  • 每次重新渲染,不需要为静态子树创建新节点
  • 虚拟DOM中patch时,可以跳过静态子树

4.代码生成

根据AST和优化后的结果,编译器会生成对应的渲染函数代码。静态内容会被转换为静态的JavaScript代码,而动态内容会被转换为动态的JavaScript表达式。

5.渲染函数输出

最终生成的渲染函数代码会被包含在最终的构建文件中,用于在组件渲染时生成虚拟DOM并更新页面。

vue2运行时动态生成render函数

在 Vue 2 中,当组件没有提供 render 函数在编译阶段没有编译好的 render 函数时,那么在组件实例化时会动态生成 render 函数。这个 render 函数会在运行时生成,并且会被挂载到组件实例的 $options 对象上的 render 属性中。

具体来说,Vue 会检查组件选项中的 render 方法。如果存在 render 方法,Vue 会调用该方法来动态生成 render 函数。这个 render 方法可以返回一个用于渲染组件的虚拟 DOM 树。

因此,在运行时动态生成 render 函数时,Vue 会调用组件实例的 $options.render 方法来生成 render 函数。这个方法的返回值将用于渲染组件的内容。

vue3的模板编译

Vue 3 在 render 函数方面相比 Vue 2 进行了一些改进和优化,在性能优化方面主要有两点改变

  1. 静态树提升(Static Tree Hoisting): Vue 3 在编译阶段会对模板进行静态分析,将静态节点提升为常量,减少渲染时的节点比对和更新操作,提高性能。
  2. 事件侦听器缓存(Event listener caching): Vue 3 会对事件侦听器进行缓存,避免每次渲染都重新创建事件侦听器,减少性能开销

vue3模板编译过程

  1. parse 模板解析: 首先会调用 parse 方法,将模板源码解析为 AST(抽象语法树)的树形结构。AST 是对模板的抽象表示,方便后续的处理和转换。

  2. transform AST 转换: 接着可能会调用一系列的 transform 方法,对 AST 进行一些转换和优化操作。这些转换可以包括静态节点提升、插槽处理、指令转换等。

  3. generate 代码生成: 经过 AST 转换后,会调用 generate 方法,将经过处理后的 AST 节点转换为渲染函数的代码字符串。这个过程会将 AST 节点转换为可执行的 JavaScript 代码。

  4. 优化代码: 可能会对生成的代码进行一些优化,例如进行尾部优化、静态节点提升等,以提高渲染函数的性能。

  5. 返回 CodegenResult: 最终将生成的代码字符串以及其他相关信息(如错误信息、提示等)封装在 CodegenResult 对象中返回,供后续使用。

 render伪代码

compileToFunction伪代码

function compileToFunction(template, options) {
  const key = template;
  const cache = new Map();

  if (cache.has(key)) {
    return cache.get(key);
  }

  const { code } = compile(template, options); // 假设 compile 函数可以将模板编译成代码

  const render = new Function('Vue', code)(Vue); // 假设 Vue 是运行时的 Vue 实例

  // 标记函数为已编译
  render._rc = true;

  cache.set(key, render);

  return render;
}
function baseCompiler(source,options){
    const ast = baseParse(source,options);//生成ast语法树
    transform(ast,...)//对ast进行一个优化
    return generate(ast,options);//返回generate生成code
}

vue3源码实现

源码中,compileToFunction方法的实现位于core-main\packages\vue\src\index.ts文件中

compileToFunction方法

vue3模板编译的核心仍然是compileToFunction 函数,将template模板转换成render函数。

整个过程可以分为以下几个步骤: 

  1. 传入模板和选项参数: 函数接受两个参数,一个是模板 template,另一个是选项参数 options
  2. 生成缓存键值: 将传入的模板作为键值 key,用于缓存已经编译过的模板函数。
  3. 检查缓存: 使用 cache Map 对象来检查是否已经缓存了该模板对应的函数,如果有,则直接返回缓存的函数。
  4. 模板编译: 调用 compile 函数对传入的模板进行编译,得到编译后的代码 code。这里假设 compile 函数是一个能够将模板编译成代码的函数。
  5. 创建函数: 使用 new Function 构造函数,将编译后的代码作为函数体,生成一个新的函数 render。这个函数在运行时将会接收一个 Vue 实例作为参数。
  6. 执行函数: 调用生成的函数 render,并传入 Vue 实例作为参数,得到最终的渲染函数。
  7. 标记函数: 将生成的渲染函数标记为已编译,以便下次可以直接从缓存中获取。
  8. 缓存函数: 将生成的渲染函数存入缓存中,以备下次使用。
  9. 返回函数: 返回生成的渲染函数。

核心调用了compile方法,compile又调了baseCompile方法

baseCompiler方法

关键方法还是看baseCompile方法。在 Vue 3 的 baseCompile 函数中,主要完成了将模板源码编译为渲染函数的过程。

整个过程可以分为以下几个步骤: 

parse 模板解析

首先会调用 parse 方法,将模板源码解析为 AST(抽象语法树)的树形结构。AST 是对模板的抽象表示,方便后续的处理和转换。

transform AST 转换

接着可能会调用一系列的 transform 方法,对 AST 进行一些转换和优化操作。这些转换可以包括静态节点提升、插槽处理、指令转换等。

generate 代码生成

经过 AST 转换后,会调用 generate 方法,将经过处理后的 AST 节点转换为渲染函数的代码字符串。这个过程会将 AST 节点转换为可执行的 JavaScript 代码。

优化代码

可能会对生成的代码进行一些优化,例如进行尾部优化、静态节点提升等,以提高渲染函数的性能。

返回 CodegenResult

最终将生成的代码字符串以及其他相关信息(如错误信息、提示等)封装在 CodegenResult 对象中返回,供后续使用。

如何查看打包后的render函数?

在 Vue 项目中,不论是编译时还是运行时,打包后的构建文件通常都会包含 render 函数。区别在于编译时生成的 render 函数是静态的,而运行时生成的 render 函数是动态的。

具体来说:

  1. 编译时生成的 render 函数:在编译阶段,Vue 的编译器会将模板(template)编译为静态的 render 函数。这个静态 render 函数会被包含在最终的构建文件中,用于在组件渲染时生成虚拟 DOM。

  2. 运行时生成的 render 函数:有时候,Vue 组件可能会在运行时动态生成 render 函数,特别是在动态组件或函数式组件的情况下。这些动态生成的 render 函数通常不会在编译时静态生成,而是在组件实例化或渲染时动态生成。

打包 Vue 项目时,通常会将 Vue 组件中的模板(template)转换为渲染函数(render function),然后将这些渲染函数打包到最终的构建文件中。如果想查看 render 函数被打包到哪里了,可以按照以下步骤进行:

  1. 查看构建输出文件

    • 查看生成的构建文件,通常在 dist 目录下。
    • 打开生成的构建文件,查找包含 Vue 组件代码的文件,通常是经过处理的 JavaScript 文件。
  2. 搜索渲染函数代码

    • 在构建文件中搜索 Vue 组件的代码,特别是包含 render 函数的部分。
    • 渲染函数通常会以函数的形式存在,搜索关键字如 render: function 或 render() { 来找到渲染函数所在的位置

思考:一个template对应一个render函数吗?

在 Vue 中,一个 template 可以对应多个 render 函数。在 Vue 的编译过程中,一个 template 会被编译为一个 render 函数,这个 render 函数用于生成组件的虚拟 DOM。然而,有时候一个 template 也可以对应多个 render 函数,这取决于 Vue 组件的定义方式和使用场景。

  1. 单文件组件:在 Vue 单文件组件中,通常一个 template 会对应一个 render 函数。这是因为单文件组件中的 template 会被编译为一个 render 函数,并且在组件的定义中只会有一个 render 函数。

  2. 动态组件:在某些情况下,一个 template 可能会对应多个 render 函数,特别是在动态组件的情况下。动态组件可以根据不同的条件或状态渲染不同的组件,每个组件可能有不同的 template 和 render 函数。

  3. 函数式组件:在函数式组件中,通常不会有 template,而是直接使用 render 函数来定义组件的渲染逻辑。

思考:打包后的每个.js文件都会有render函数吗?

在 Vue 项目中,经过编译和打包后的每个 .js 文件并不一定都会包含 render 函数。Render 函数通常是在 Vue 单文件组件中定义的,然后经过编译器编译为 JavaScript 代码,并最终打包到构建文件中。

具体来说:

  1. 单文件组件:在 Vue 单文件组件中,通常会包含 template 和 render 函数。编译器会将 template 编译为 render 函数,并将这个 render 函数包含在最终的构建文件中。

  2. 普通 JavaScript 文件:在普通的 JavaScript 文件中,如果没有定义 Vue 组件或没有使用 render 函数,那么这些文件通常不会包含 render 函数。

  3. 动态组件和函数式组件:动态组件和函数式组件可能会在运行时动态生成 render 函数,这些 render 函数可能不会在打包后的每个 .js 文件中静态存在,而是根据需要动态生成。

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

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

相关文章

SAP FI学习笔记03 - 应付账款

上一章讲了MM与FICO的集成。 SAP FI学习笔记02 - 基础知识 - MM与FICO集成-CSDN博客 本章讲应付账款。 上一章也讲了应付账款&#xff08;買掛金&#xff09;&#xff0c;它的来源可以是 - 购买发注&#xff0c;入库&#xff0c;请求书照合 之后系统自动生成 &#xff08;具…

南京大学提出用于大模型生成的动态温度采样法,简单有效!

在自然语言处理&#xff08;NLP&#xff09;的领域&#xff0c;大语言模型&#xff08;LLMs&#xff09;已经在各种下游语言任务中展现出了卓越的性能。这些任务包括但不限于问答、摘要、机器翻译等。LLMs的强大能力在于其生成的文本质量和多样性。为了控制生成过程&#xff0c…

任意文件下载漏洞

1.文件下载漏洞存在的位置 文件经过php处理可能存在文件下载漏洞&#xff0c;配合目录遍历漏洞使用 2.目录遍历漏洞检验方法 测试是否存在目录遍历漏洞&#xff1a;在网站网址中间添加随意写一个文件名../&#xff08;返回上一级&#xff09;进行测试&#xff0c;没有报错就…

UART通信

UART——通用异步收发传输器&#xff0c;UART 作为异步串口通信协议的一种&#xff0c;工作原理是将传输数据的每个字符一位接一位地传输。在应用程序开发过程中使用频率较高的数据总线。 基于UART的数据传输是异步形式的串行数据传输。基于UART的串行数据传输不需要使用时钟信…

基于springboot+vue实现的酒店客房管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

[Python学习篇] Python创建项目

新建项目 打开开发工具 PyCharm 选择 New Project 目录结构如下 运行 hello world 选中项目&#xff0c;右键 New -> Python File 进行创建文件 运行项目

STM32学习和实践笔记(4): 分析和理解GPIO_InitTypeDef GPIO_InitStructure (b)

继续上篇博文&#xff1a;STM32学习和实践笔记&#xff08;4&#xff09;: 分析和理解GPIO_InitTypeDef GPIO_InitStructure (a)-CSDN博客 往下写&#xff0c; 为什么&#xff1a;当GPIO_InitStructure.GPIO_PinGPIO_Pin_0 ; 时&#xff0c;其实就是将对应的该引脚的寄存器地…

Python搭建编程环境—安装Python3解释器

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;零基础学Python &#x1f4ac;个人格言&#xff1a;不断的翻越一…

HarmonyOS 应用开发之启动指定页面

当PageAbility的启动模式设置为单例时&#xff08;具体设置方法和典型场景示例见 PageAbility的启动模式 &#xff0c;缺省情况下是单实例模式&#xff09;&#xff0c;若PageAbility已被拉起&#xff0c;再次启动PageAbility会触发onNewWant回调&#xff08;即非首次拉起&…

JavaScript基础代码练习之冒泡排序

一、要求对一个数组进行冒泡排序&#xff0c;并将排序后的结果输出到控制台。在代码中&#xff0c;数组 arr 包含了一组数字&#xff0c;然后使用嵌套的循环来进行冒泡排序。 二、编写代码 <!DOCTYPE html> <html lang"en"><head><meta chars…

doccano标注工具|为机器学习建模做数据标注

目录 一、标记流程 二、配置环境 2.1 安装 2.2 运行doccano 三、案例 3.1 创建项目 3.2 上传数据 3.3 定义标签 3.4 添加成员 3.5 开始标注 3.6 导出数据 3.7 导出数据 doccano doccano是开源的数据…

【C++进阶】AVL树(来自二叉搜索树的复仇)

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 总有光环在陨落&#xff0c;总有新星在闪烁 引言&#xff1a; 之前我们学…

每日面经分享(Spring Boot: part3 Service层)

SpringBoot Service层的作用 a. 封装业务逻辑&#xff1a;Service层负责封装应用程序的业务逻辑。Service层是控制器&#xff08;Controller&#xff09;和数据访问对象&#xff08;DAO&#xff09;之间的中间层&#xff0c;负责处理业务规则和业务流程。通过将业务逻辑封装在S…

什么是智慧驿站?智慧驿站主要应用有哪些?新型智慧公厕解说

智慧驿站是一种融合了创意设计和多项功能的新型智慧公厕&#xff0c;它在信息化公共厕所的基础上&#xff0c;以创意的外观设计、全金属结构用材、快速制作整体运输、快速部署落地使用等价值特点&#xff0c;所打造了一个集购物、互动、休憩等多种功能于一体的城市基础设施。无…

【智能算法】金枪鱼群优化算法(TSO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.代码展示4.参考文献 1.背景 2021年&#xff0c;Xie等人受到自然界中金枪鱼狩猎行为启发&#xff0c;提出了金枪鱼优化算法&#xff08;Tuna swarm optimization&#xff0c;TSO&#xff09;。 2.算法原理 2.1算法思想 TSO模…

Rust语言中Regex正则表达式,匹配和查找替换等

官方仓库&#xff1a;https://crates.io/crates/regex 文档地址&#xff1a;regex - Rust github仓库地址&#xff1a;GitHub - rust-lang/regex: An implementation of regular expressions for Rust. This implementation uses finite automata and guarantees linear tim…

LCD1602显示屏

LCD1602显示 概述 LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 引脚说明 //电源 VSS -- GND VDD -- 5V //对比度 VO -- GND //控制线 RS -- P1.0 RW -- P1.1 E -- P1.4 //背光灯 A -- 5…

Python快速入门系列-8(Python数据分析与可视化)

第八章:Python数据分析与可视化 8.1 数据处理与清洗8.1.1 数据加载与查看8.1.2 数据清洗与处理8.1.3 数据转换与整理8.2 数据可视化工具介绍8.2.1 Matplotlib8.2.2 Seaborn8.2.3 Plotly8.3 数据挖掘与机器学习简介8.3.1 Scikit-learn8.3.2 TensorFlow总结在本章中,我们将探讨…

在Java中对SQL进行常规操作的通用方法

SQL通用方法 一、常规方法增删改查二、具体优化步骤1.准备工作2.getcon()方法&#xff0c;获取数据库连接对象3.closeAll()方法&#xff0c;关闭所有资源4.通用的增删改方法5.通用的查询方法6.动态查询语句 总结 一、常规方法增删改查 在常规方法中&#xff0c;我们在Java中对…

rocketmq的运维

1. admintool创建topic的时候 -o 的用法含义 https://rocketmq.apache.org/zh/docs/4.x/producer/03message2/ 有关orderMessageEnable和returnOrderTopicConfigToBroker的设置可以参考 https://blog.csdn.net/sdaujsj1/article/details/115741572 -c configFile通过-c命令指…