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

【小程序 - 大智慧】Expareser 组件渲染框架

5.png


目录

  • 问题思考
  • 课程目标
  • Web Component
    • 类型说明
    • 定义组件
    • 属性添加
  • Shadow DOM
  • Template and Slot
  • Exparser 框架原理
    • 自定义组件
    • 内置组件
  • 下周计划


问题思考

首先,给大家抛出去几个问题:

  1. 前端框架 Vue React 都有自己的组件库,但是并不兼容,那么 不依赖框架能 自定义组件 吗?
  2. 微信小程序开发的时候都会自定义组件是吧,那么调试控制台出现的 shadow-root 是什么,有注意吗?
  3. 微信小程序编写 wxml 的时候,为什么和 html 语法不一致,多出来 view text 这些标签,里面究竟是如何实现的,彼此有什么关联?

课程目标

通过本节课程的学习,希望大家掌握如下的目标:

  1. 弄懂上述问题背后的执行逻辑
  2. 能够利用原生 Web Component 自定义一个简易的组件

Web Component

使用自定义元素 - Web API | MDN

Web Component直译过来就是 web 组件的意思,就是说明离开了前端框架的帮助,我们依然可以用原生组件来进行开发复用。

类型说明

如同官网所说,继承特定元素类得到的组件是 自定义内置元素组件(可以得到特定类型的属性和方法),继承元素基类得到的组件是 独立自定义元素,本质上两种没什么区别,接下来我们重点就放在第二个上面。

定义组件

<button is="my-button-one">内置按钮</button>
<my-button-two></my-button-two>// 01 定义一个内置元素的按钮
class MyButtonOne extends HTMLButtonElement {constructor() {self = super();}// 元素添加到文档调用connectedCallback() {// 1.创建一个 divconst div = document.createElement("div");// 2.设置 div 的样式div.style.width = "100px";div.style.height = "50px";div.style.textAlign = "center";div.style.lineHeight = "50px";div.style.cursor = "pointer";self.style.marginBottom = "20px";// 3.设置 div 的内容div.innerHTML = "自定义按钮";// 4.将 div 添加到页面self.appendChild(div);}
}// 02 定义一个自定义的按钮
class MyButtonTwo extends HTMLElement {constructor() {// 先调用父类构造器,实例化 HTMLElement ,这样才能有 html 元素的基本属性super();}// 元素添加到文档调用connectedCallback() {console.log("自定义元素添加到页面", this);// 1.创建一个 divconst div = document.createElement("div");// 2.设置 div 的样式div.style.width = "100px";div.style.height = "50px";div.style.backgroundColor = "red";div.style.color = "white";div.style.textAlign = "center";div.style.lineHeight = "50px";div.style.cursor = "pointer";// 3.设置 div 的内容div.innerHTML = "自定义按钮";// 4.将 div 添加到页面this.appendChild(div);}// 元素从文档中移除时调用disconnectedCallback() {console.log("自定义元素从页面移除");}// 元素被移动到新文档时调用adoptedCallback() {console.log("自定义元素被移动到新文档");}// 监听属性变化attributeChangedCallback(name, oldValue, newValue) {console.log(`属性 ${name} 已由 ${oldValue} 变更为 ${newValue}`);}
}// 组件注册
customElements.define("my-button-one", MyButtonOne, { extends: "button" });
customElements.define("my-button-two", MyButtonTwo);// 监听组件状态
customElements.whenDefined("my-button-two").then(() => {console.log("my-button-two 组件已定义");
});

自定义组件的命名规则是有限制的:

  • 自定义元素的名称,必须包含短横线(-)。它可以确保html解析器能够区分常规元素和自定义元素,还能确保html标记的兼容性。
  • 自定义元素只能一次定义一个,一旦定义无法撤回。
  • 自定义元素不能单标记封闭。比如 <custom-component />,必须写一对开闭标记。比如 <custom-component></custom-component>

上面两个就是最基本的自定义组件,但是这个也没有样式 class 属性传值 事件方法都没有,下面我们一步步加上。

属性添加

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><style>* {margin: 0;padding: 0;}body {width: 100px;margin: 200px auto;background-color: #f5f5f5;}.my-button-two {width: 180px;height: 50px;background-color: red;color: white;text-align: center;line-height: 50px;cursor: pointer;}</style><my-button-two color="pink" text="Custom Component" @click="clickButton()"></my-button-two><title>02_属性添加</title></head><body><script>// 自定义方法const clickButton = () => {alert("点击了自定义按钮");};class MyButtonTwo extends HTMLElement {// 监控属性变化static observedAttributes = ["color", "text", "@click"];constructor() {// 先调用父类构造器,实例化 HTMLElement ,这样才能有 html 元素的基本属性super();}// 元素添加到文档调用connectedCallback() {// 1.创建一个 divconst div = document.createElement("div");// 2.设置 div 的样式div.className = "my-button-two";// 3.设置 div 的内容const bgColor = this.getAttribute("color");const textValue = this.getAttribute("text");const clickValue = this.getAttribute("@click");// 需要在同一个 js 执行环境内部执行div.addEventListener("click", () => {eval(clickValue);});div.style.backgroundColor = bgColor;div.innerHTML = textValue;// 4.将 div 添加到页面this.appendChild(div);}// 元素从文档中移除时调用disconnectedCallback() {console.log("自定义元素从页面移除");}// 元素被移动到新文档时调用adoptedCallback() {console.log("自定义元素被移动到新文档");}// 监听属性变化attributeChangedCallback(name, oldValue, newValue) {console.log(`属性 ${name} 已由 ${oldValue} 变更为 ${newValue}`);}}customElements.define("my-button-two", MyButtonTwo);// 监听组件状态customElements.whenDefined("my-button-two").then(() => {console.log("my-button-two 组件已定义");});</script></body>
</html>

对着调试控制台我们可以发现,当前 html 写的样式可以影响到组件内部,这并不符合我们之前说的组件和外部彼此 属性隔离 的特点,这就需要了解到下一个概念了。

Shadow DOM

使用影子 DOM - Web API | MDN

影子 DOM(Shadow DOM)允许你将一个 DOM 树附加到一个元素上,并且使该树的内部对于在页面中运行的 JavaScriptCSS 是隐藏的。

在这里插入图片描述

有一些 影子 DOM 术语 需要注意:

  • 影子宿主(Shadow host):影子 DOM 附加到的常规 DOM 节点。
  • 影子树(Shadow tree):影子 DOM 内部的 DOM 树。
  • 影子边界(Shadow boundary):影子 DOM 终止,常规 DOM 开始的地方。
  • 影子根(Shadow root):影子树的根节点。

这里的 影子宿主(Shadow host) 可以选取普通的 div 标签,但是由于我们是自定义元素,这里的 挂载节点 就是 自定义组件 Web Component 了,接下来我们举一个例子:

const shadow = this.attachShadow({ mode: "open" });// 这里的 this 就是标识 自定义组件 DOM 元素
// mode 分为 open closed 表示能否通过 dom.shadowRoot 获取
// 不能获取的话,只能在内部通过 shadow 访问了
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><style>* {margin: 0;padding: 0;}body {width: 100px;margin: 200px auto;background-color: #f5f5f5;}.my-button-two {width: 180px;height: 50px;background-color: red;color: white;text-align: center;line-height: 50px;cursor: pointer;}</style><my-button-two color="pink" text="Custom Component" @click="clickButton()"></my-button-two><title>03_shadow dom</title></head><body><script>// 自定义方法const clickButton = () => {alert("点击了自定义按钮");};class MyButtonTwo extends HTMLElement {// 监控属性变化static observedAttributes = ["color", "text", "@click"];constructor() {// 先调用父类构造器,实例化 HTMLElement ,这样才能有 html 元素的基本属性super();}// 元素添加到文档调用connectedCallback() {// 隔离 DOMconst shadow = this.attachShadow({ mode: "open" });// 1.创建一个 divconst div = document.createElement("div");// 2.设置 div 的样式div.className = "my-button-two";// 3.设置 div 的内容const bgColor = this.getAttribute("color");const textValue = this.getAttribute("text");const clickValue = this.getAttribute("@click");// 需要在同一个 js 执行环境内部执行div.addEventListener("click", () => {eval(clickValue);});div.style.backgroundColor = bgColor;div.innerHTML = textValue;// 4.将 div 添加到页面shadow.appendChild(div);}// 元素从文档中移除时调用disconnectedCallback() {console.log("自定义元素从页面移除");}// 元素被移动到新文档时调用adoptedCallback() {console.log("自定义元素被移动到新文档");}// 监听属性变化attributeChangedCallback(name, oldValue, newValue) {console.log(`属性 ${name} 已由 ${oldValue} 变更为 ${newValue}`);}}customElements.define("my-button-two", MyButtonTwo);// 监听组件状态customElements.whenDefined("my-button-two").then(() => {console.log("my-button-two 组件已定义");});</script></body>
</html>

这里我们可以看到 文档的样式已经无法影响我们的自定义组件了,这是因为被 shadow 阻隔了,接下来就可以继续完善这段逻辑了。

Template and Slot

使用模板和插槽 - Web API | MDN

前端组件开发中有两套我们熟悉的 Template(模板)和 Slot(插槽),接下来就利用这两个功能继续完善一下我们的代码逻辑。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><style>* {margin: 0;padding: 0;}body {width: 100px;margin: 200px auto;background-color: #f5f5f5;}.my-button-two {width: 180px;height: 50px;background-color: red;color: white;text-align: center;line-height: 50px;cursor: pointer;}</style><template id="button-template"><style>.my-button-two {width: 180px;height: 50px;background-color: red;color: white;text-align: center;line-height: 50px;cursor: pointer;}</style><div class="my-button-two"><slot name="text"></slot></div></template><my-button-two id="my-button-two" color="pink" @click="clickButton()"><span slot="text">Custom Component</span></my-button-two><title>04_Tempalte and Slot</title></head><body><script>// 自定义方法const clickButton = () => {alert("点击了自定义按钮");};class MyButtonTwo extends HTMLElement {// 监控属性变化static observedAttributes = ["color", "text", "@click"];constructor() {// 先调用父类构造器,实例化 HTMLElement ,这样才能有 html 元素的基本属性super();}// 元素添加到文档调用connectedCallback() {// 隔离 DOMconst shadow = this.attachShadow({ mode: "closed" });// 1.获取模板const template = document.querySelector("#button-template");// 2.克隆模板const content = template.content.cloneNode(true);// 3.显示文本const clickValue = this.getAttribute("@click");// 4.执行函数const clickEvent = content.querySelector(".my-button-two");clickEvent.addEventListener("click", () => {eval(clickValue);});// 5.将 template 添加到页面shadow.appendChild(content);}// 元素从文档中移除时调用disconnectedCallback() {console.log("自定义元素从页面移除");}// 元素被移动到新文档时调用adoptedCallback() {console.log("自定义元素被移动到新文档");}// 监听属性变化attributeChangedCallback(name, oldValue, newValue) {console.log(`属性 ${name} 已由 ${oldValue} 变更为 ${newValue}`);}}customElements.define("my-button-two", MyButtonTwo);// 监听组件状态customElements.whenDefined("my-button-two").then(() => {console.log("my-button-two 组件已定义");});</script></body>
</html>

艺龙酒店科技官网

举例 video 标签就是利用这套机制封装的…

Exparser 框架原理

Exparser 是微信小程序的组件组织框架,内置在小程序基础库中,为小程序提供各种各样的组件支撑。内置组件和自定义组件都有 Exparser 组织管理。

Exparser 的组件模型与 WebComponents 标准中的 Shadow DOM 高度相似,Exparser 会维护整个页面的节点树相关信息,包括节点的属性、事件绑定等,相当于一个简化版的 Shadow DOM 实现。Exparser 的主要特点包括以下几点:

  • 基于 Shadow DOM 模型:模型上与 WebComponentsShadow DOM 高度相似,但不依赖浏览器的原生支持,也没有其他依赖库;实现时,还针对性地增加了其他 API 以支持小程序组件编程。
  • 可在纯 JS 环境中运行:这意味着逻辑层也具有一定的组件树组织能力。
  • 高效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同时代码尺寸也较小。

自定义组件

上图是小程序利用 shadow dom 实现 样式和JS 逻辑隔离的组件,这只是第一层,里面的 view text 也是由 Exparser 从普通 div span 封装得来的,接下来让我们深入了解下:

内置组件

接下来带大家一步步过一遍微信小程序内置组件是如何渲染的

// 1.在微信开发工具找到解析命令 wcc
// wcc 是将 wxml 解析为 js 文件,然后逻辑线程注入 webview 执行的
微信web开发者工具\code\package.nw\node_modules\wcc-exec// 2.将命令文件移动到文件目录下,开始执行解析
./wcc -js index.wxml >> dom.js

  • 可以看到本质上就是一个封装好的 $gwx 函数,它的作用是生成微信自定义的组件和虚拟 dom 节点( diff 算法),用来给后面的 Exparser 生成真实的 DOM 节点
  • 那这个函数是在哪里调用的呢,我们继续向下看
// 1. 调试控制台打开当前页面的 webview
document.getElementsByTagName('webview')
document.getElementsByTagName('webview')[0].showDevTools(true, null)// 2. 可以发现编译后的 wxml 会利用 js 脚本以一定格式插入到页面中执行
var decodeName = decodeURI("./pages/command_component/index.wxml")
var generateFunc = $gwx(decodeName)generateFunc()// 3.传入数据
generateFunc({logs:[1,2,3]})


<view wx:for="{{ logs }}" wx:key="index"><text>{{ item }}</text>
</view>

可以看到如上图所示的虚拟节点数组,接下来我们详细剖析一下

  1. $gwx(decodeName) 不直接返回 dom 树,而是返回一个函数的原因是因为需要动态注入和相关配置,函数能够很好的把控时机
  2. 利用动态传参我们发现,包含循环数组和 key 的会带有 virtual 标识,用来后面的 DIff 算法比较
  3. document.dispatchEvent 触发自定义事件 将 generateFunc 当作参数传递给底层渲染库

  1. 可以看得到无论是 view 还是 text 底层都是通过 div span 的自定义组件构成的
  2. 这一切来源于 Exparser 框架,在 渲染层 会内置一系列方法,大致和上面自定义 web component 一致,进行对组件的定义,注册后将 js 脚本引入页面,那么当前页面就可用了
  3. 接下来带大家进行源码的拆解

下周计划

  1. 继续深入小程序原理(收益不高)
  2. 扩展前端其他的技术方向(感兴趣建议)
    1. 前端组件库实现拆解
    2. 前端调试能力提升
    3. 前端工程化能够了解

相关文章:

【小程序 - 大智慧】Expareser 组件渲染框架

目录 问题思考课程目标Web Component类型说明定义组件属性添加 Shadow DOMTemplate and SlotExparser 框架原理自定义组件内置组件 下周计划 问题思考 首先&#xff0c;给大家抛出去几个问题&#xff1a; 前端框架 Vue React 都有自己的组件库&#xff0c;但是并不兼容&#…...

vue + echarts 快速入门

vue echarts 快速入门 本案例即有nodejs和vue的基础&#xff0c;又在vue的基础上整合了echarts Nodejs基础 1、Node简介 1.1、为什么学习Nodejs(了解) 轻量级、高性能、可伸缩web服务器前后端JavaScript同构开发简洁高效的前端工程化 1.2、Nodejs能做什么(了解) Node 打破了…...

服务器几核几G几M是什么意思?如何选择?

服务器几核几G几M是什么意思&#xff1f;我们建站、搭建网络平台都要用到云服务器&#xff0c;不管在腾讯云、阿里云还是别的云服务平台选购&#xff0c;都会接触到服务器配置。云服务器就是把物理服务器&#xff08;俗称“母鸡”&#xff09;&#xff0c;用虚拟机技术虚拟出多…...

K8S服务发布

一 、服务发布方式对比 二者主要区别在于&#xff1a; 1、部署复杂性&#xff1a;传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等&#xff0c;过程相对复 杂且容易出错。相比之下&#xff0c;Kubernetes服务发布方式 通过使用容器编排和自动化部署工…...

Allen Institute for Artificial Intelligence (Ai2) 发布开源多模态语言模型 Molmo

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

Html CSS 布局,位置处理 居中 对齐

Html CSS 布局&#xff0c;位置处理 1、居中布局 1、div 让内部div居中对齐 html <div class"container"><div class"item">I am centered!</div> </div>style .container {border: 2px solid rgb(75, 70, 74);border-radius:…...

Spring MVC系统学习(二)——Spring MVC的核心类和注解

Spring MVC&#xff08;Model-View-Controller&#xff09;是Spring框架的一个模块&#xff0c;用于构建基于Web的应用程序。它使用模型、视图和控制器分离的设计模式&#xff0c;使得Web开发更加模块化和灵活。在学习Spring MVC时&#xff0c;有几个核心类和注解是非常关键的&…...

conda虚拟环境安装包、依赖同一管理

在 Python 的虚拟环境中&#xff0c;每个环境都是独立的&#xff0c;这意味着即使两个环境需要相同的库&#xff0c;它们也会分别安装各自的副本。这样做是为了避免不同项目之间相互影响&#xff0c;确保每个项目都有一个干净且隔离的环境。 方法一&#xff1a;使用 Conda 的共…...

Unity网络开发记录(四):在unity中进一步封装客户端类

在上一篇文章中&#xff0c;简单的封装了一下服务端中相关的socket对象&#xff0c;为了可以更方便的使用。所以在本篇中&#xff0c;进一步封装一下在unity中的相关客户端类 封装客户端类&#xff0c;首先采用单例模式&#xff0c;然后采用两个队列来存储我们相关的收发信息 p…...

Linux内核中的UART驱动-详解Linux内核UART驱动:结构与功能分析

一、UART概述 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff09;&#xff0c;即通用异步收发器&#xff0c;是一种串行通信接口&#xff0c;用于在计算机和外部设备之间传输数据。它特别适用于短距离、低速、串行和全双工的数据传输。在Linux内核中&a…...

威胁检测与防范:如何及时、准确对抗安全风险

随着技术的飞速发展&#xff0c;网络空间中的威胁日益多样化、隐蔽化&#xff0c;给个人、企业乃至国家的信息安全带来诸多挑战。面对严峻的网络威胁&#xff0c;传统的防火墙、入侵检测系统&#xff08;IDS&#xff09;等防御手段虽能在一定程度上抵御外部攻击&#xff0c;但依…...

数据结构串的kmp相关(求next和nextval)

傻瓜版&#xff0c;用来演示手算过程&#xff0c;个人理解用的&#xff0c;仅供参考。...

创建游戏暂停菜单

创建用户控件 设置样式 , 加一层 背景模糊 提升UI菜单界面质感 , 按钮用 灰色调 编写菜单逻辑 转到第三人称蓝图 推荐用 Set Input Mode Game And UI , 只用仅UI的话 增强输入响应不了 让游戏暂停的话也可以用 Set Game Paused , 打勾就是暂停 , 不打勾就是继续游戏 , 然后…...

seata服务端部署

1.下载seata 官网下载地址&#xff1a;http://seata.io/zh-cn/blog/download.html 或者下载 作者已经下载的压缩包1.4.0 注意&#xff01;&#xff01;&#xff01; 要参考对应的版本&#xff0c;否则可能出现无法正常启动的情况。 参考文档 下载完毕后解压压缩文件 2.修改配…...

理解Python闭包概念

闭包并不只是一个python中的概念&#xff0c;在函数式编程语言中应用较为广泛。理解python中的闭包一方面是能够正确的使用闭包&#xff0c;另一方面可以好好体会和思考闭包的设计思想。 1.概念介绍 首先看一下维基上对闭包的解释&#xff1a; 在计算机科学中&#xff0c;闭包…...

51单片机的教室智能照明系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块DS1302时钟模块光照传感器红外传感器温度传感器LED等模块构成。适用于教室灯光全自动控制、教室节能灯控制、教室智能照明等相似项目。 可实现功能: 1、LCD1602实时显示时间、温度、光照强度等信息 2、光照强度传…...

一款资产进行快速存活验证工具

01工具介绍 &#xff08;下载地址见最后&#xff09; 在日常工作的渗透测试过程中&#xff0c;经常会碰到渗透测试项目&#xff0c;而Web渗透测试通常是渗透项目的重点或者切入口。通常拿到正规项目授权后&#xff0c;会给你一个IP资产列表和对应的Web资产地址&#xff0c;这时…...

I/O中断处理过程

中断优先级包括响应优先级和处理优先级&#xff0c;响应优先级由硬件线路或查询程序的查询顺序决定&#xff0c;不可动态改变。处理优先级可利用中断屏蔽技术动态调整&#xff0c;以实现多重中断。下面来看他们如何运用在中断处理过程中&#xff1a; 中断控制器位于CPU和外设之…...

关于PHP 匿名函数在处理数据结构中的应用

PHP 的匿名函数&#xff08;也称为闭包&#xff09;在处理数据结构时非常有用。它们可以在需要一次性函数的情况下使用&#xff0c;例如数组函数的回调、事件处理或作为其他函数的参数。以下是一些常见的应用场景&#xff1a; 数组操作&#xff1a; 使用 array_map、array_fil…...

安卓13默认使用大鼠标 与配置分析 andriod13默认使用大鼠标 与配置分析

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android13里面的鼠标貌似比以前版本的鼠标小了,有些客户想要把这个鼠标改大。这个功能,android有现成的,就在这里,设置 =》无障碍 =》色彩和动画 =》 大号鼠标指针。 我们通过…...

AI学习指南深度学习篇-批标准化在深度学习中的应用

AI学习指南深度学习篇-批标准化在深度学习中的应用 引言 批标准化&#xff08;Batch Normalization, BN&#xff09;是一种在深度学习中常用的技术&#xff0c;旨在加速训练过程并提高模型的稳定性。它通过标准化每一个小批量的激活值&#xff0c;减小内部协变量偏移&#xf…...

了解网络的相关信息

文章目录 前言了解网络的相关信息1. ip是什么?1.1. 公网IP:1.2. 私有IP:1.2.1. 示例 2. 子网掩码3. 子网掩码的划分网段是什么4. 特殊的回路IP网段(127.0.0.1)5. 端口 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#x…...

Java | Leetcode Java题解之第447题回旋镖的数量

题目&#xff1a; 题解&#xff1a; class Solution {public int numberOfBoomerangs(int[][] points) {int ans 0;for (int[] p : points) {Map<Integer, Integer> cnt new HashMap<Integer, Integer>();for (int[] q : points) {int dis (p[0] - q[0]) * (p[…...

Docker实践与应用举例

引言 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。本文将详细介绍 Dock…...

828华为云征文 | 智能监控新篇章,Prometheus如何在华为云Flexusx容器环境中大展身手

前言 在数字化转型的浪潮中&#xff0c;智能监控成为企业IT战略的关键环节。部署在华为云Flexus X实例上的Prometheus监控系统&#xff0c;凭借其卓越的性能与灵活性&#xff0c;正开启智能监控的新篇章。Flexus X实例以其强大的计算能力和灵活的资源管理&#xff0c;为Prometh…...

基于单片机的可调式中文电子日历系统

** 文章目录 前言概要功能设计软件设计效果图 程序文章目录 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们…...

《C++设计新思维-泛型编程与设计模式之应用》阅读记录

目录 写在前面policy和policy class的认识 写在前面 这本书是2003年出版的&#xff0c;大佬侯捷翻译的&#xff0c;21年前的书了&#xff0c;最近打算翻一翻。 看这种技术书籍&#xff0c;特别是简历理论体系的书籍&#xff0c;最好看纸质书。 本书从根本上展示了generic pa…...

vue访问组件的数据和方法

组件源码 <template><view class"c_container" :style"myStyle" click"clickCust"><view style"font-size: 18px;text-align: center;">{{item.name}}</view><view style"margin-top: 10px;font-siz…...

Redis: RDB与AOF的选择和容灾备份以及Redis数据持久化的优化方案

如何选择RDB和AOF 1 &#xff09;同时开启 在我们 Redis 的服务器上&#xff0c;把RDB和AOF同时打开, 这样可以通过RDB快速的恢复数据&#xff0c;因为它是一个紧凑的缩缩的二进制文件, 但是有时 Redis 的不小心故障了&#xff0c;丢失了十几分钟的数据 可以通过AOF来做数据的…...

Goweb---Gorm操作数据库(二)

Gorm允许用户自己自定义钩子操作&#xff0c;使用这些钩子操作&#xff0c;可以在增删改查操作前进行相关的操作和检验&#xff0c;它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误&#xff0c;GORM 将停止后续的操作并回滚事务。 自定义钩子函数 package ma…...

wordpress menu插件/长沙关键词优化公司电话

这是一篇讨论Node.js在无需修改任何代码从单核垂直扩展到多核&#xff0c;再水平扩展到多台集群和消息集成的分布式系统&#xff0c;展示了Node.JS在无缝扩展性方面要强于Java。其主要架构是Node.js微服务 消息Messaging 集群Clustering 。翻译如下&#xff1a; 当使用微服务…...

通化公司做网站/搜索引擎排名竞价

第1篇&#xff1a;六年级上册数学圆的知识点整理一、认识圆1、圆的定义&#xff1a;圆是由曲线围成的一种平面图形。2、圆心&#xff1a;将一张圆形纸片对折两次&#xff0c;折痕相交于圆中心的一点&#xff0c;这一点叫做圆心。一般用字母o表示。它到圆上任意一点的距离都相等…...

中小型网站建设与管理设计总结/2023年广州疫情最新消息

如何显示文件夹中的图片&#xff0c;数据库表中&#xff0c;只记录图片名称或是图片路径。写一个用户控件&#xff0c;即轻易把图片显示出来。 另外&#xff0c;如何取得记录的主键&#xff0c;您是用HiddenField&#xff0c;DataKeyNames还是用DataRowView来取得&#xff1f; …...

微擎可以做企业网站吗/无货源网店怎么开

思路&#xff1a;将二叉树中序遍历的非递归版本拆分为函数 代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* Tr…...

刚刚邯郸发生大事了/seo公司排名

方案一&#xff1a;使用360急救箱扫描打开 360安全卫士&#xff0c;在主界面右侧点击“功能大全(更多)”&#xff0c;找到并打开“系统急救箱”。等360系统急救箱安装并更新完成后&#xff0c;点击右侧的“系统设置修复区”点击“全选”按钮后&#xff0c;点击“扫描修复”按钮…...

贵南县wap网站建设公司/综合搜索引擎

单例模式用于当一个类只能有一个实例的时候&#xff0c; 通常情况下这个“单例”代表的是某一个物理设备比如打印机&#xff0c;或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。用单例模式加以控制是非常有必要的。 单例模式需要达到…...