苹果核 - 页面动态化的基础 —— Tangram

2023-10-31

12月10日在SFDC(SegmentFault Developer Conference)大会上初次介绍了手机天猫的Tangram方案,现场时间有限,讲得匆忙,特此整理记录。这篇内容是Tangram的整体介绍与相关业务开发实践的介绍,后续逐步会将更详细的方案整理成文分享出来。

1. 什么是Tangram

标题

顾名思义,Tangram中文名是七巧板的意思,我们希望这个框架提供一系列基本单元,就像积木块一样,通过快速拼装就能搭建出一个页面或者调整页面的结构。重运营的业务特别是电商业务,往往讲究灵活多变,需要对线上业务做实时调整,此类页面动态化的需求便应运而生。

2. Tangram的设计理念

设计理念

对于客户端开发来说,版本发出去之后,再要修改代码,是一件成本比较高的事情,针对线上实时调整比较多的地方,往往就采用了H5的方式上线。由于H5的体验相对Native欠缺一些,就有了后来Facebook的ReactNative(RN),以及阿里自己的解决方案Weex,以Native的方式实现页面动态调整的能力。在如今,表面上看起来Tangram的方案会有些多余,但是通过了解它的设计与演变,那就知道它还是有存在的理由。

在历史上,大概两年前的这个时候,我们团队接手天猫首页的业务,迫切需要一套页面动态化方案。那个时候RN刚刚面世不久,特别是Android版本的RN还不稳定,更不用说后来的Weex了。而我们手里有的一套方案是自己开发过的Dynative(可以理解为初级版本的Weex)。但这些方案有个共同点就是比较重量级,它们都期望从基本的UI元素开始做一套纯动态的方案。在种种现有框架不成熟的时候,对于首页这种重量级的页面,我们还是希望以一种更加纯粹的Native开发模式来支撑业务。

在设计理念上,Tangram也有它的特殊之处,无论是H5还是Weex之类的方案,它们的动态能力在于随时可发布代码,它们是面向开发的动态化方案,发布代码异味着测试、灰度、发布等一系列流程。而Tangram是面向运营和产品的方案,它的动态能力体现在无须做代码改动,提供足够多的动态可配置的能力,通过在后台做样式的调整来达到页面调整的目的。所以简单比较如下:

H5 Weex/RN Tangram
动态能力 较强
面向人员 开发 开发
体量 完善的体系 较重量级
体验 常规H5体验 鉴于H5和native之间

鉴于这样的设计目标,在这个框架里,重点有四个方面的抓手:

  1. 页面布局动态化,意思是页面的排版布局,可以通过后端数据的下发来调整。
  2. 组件业务化,这里的组件不是指基本的文本、图片、按钮等基本UI控件,而是指能承担一定业务能力的最小复用单元,因此它可能是一个文本和一个图片的组合这样子的一种形式。
  3. 动态能力粗粒度化,通过布局+组件的形式搭建整个页面,有多少种布局能力是内置在框架里的,有多少组件也是业务接入的时候注册到框架里的,后端下发的数据声明了用哪些布局、用哪些组件,通过布局嵌套组件的形式渲染整个页面。所以这个动态能力比较粗,不像H5或者Weex从基本的UI元素开始搭建整个页面。
  4. 组件的复用,为了承载那些个超长页面,需要对同类型的组件具备回收复用的能力,就像ListViewRecyclerView那样。

3. Tangram里重要的概念模型

3.1 页面拆解

页面拆解

从一个实例出发,上图中展示的是一个早期的天猫首页,根据导购页面的特点,我们将页面拆分成三个层次:页面——卡片——组件,页面(第一张图)指的就是整体可滑动页面实体,并没有特殊之处;卡片指的是页面内可按行划分的一个一个独立区块(参考第二张图),组件(参考第三张图)指的是卡片内部一个独立的、业务级别的单元,它可以是一张图,也可以是文字+图的组合。因此整体整个页面可以这样描述:一个页面嵌套了多个卡片,一个卡片嵌套了多个组件。

3.2 页面结构

页面结构

通过将页面拆分成三层结构,整个页面在model上就可以描述成这样一个树状结构。这里最重要的两个model是卡片和组件的model,整个页面的动态化将通过它们的动态化以及它们之间组合关系的动态化来完成。下面看这两层的具体协议描述:

3.3 卡片模型

卡片的协议

卡片的职责是负责对组件进行布局,那么如何描述布局呢,前面说过,我们采用的是粗粒度的动态化方式,卡片的布局描述就是一种声明式的方式,因此卡片不需要布局模板,只要在model的数据里描述卡片的类型即可,至于卡片有哪些类型,则是注册在Tangram框架里的,业务方在接入框架的时候也可以注册自定义的卡片类型。这样就让Tangram省去了对布局模板的解析,简化了框架复杂度的同时,简化了开发复杂度。

卡片model描述上有四个组成:header、footer、body、style。最重要的是body部分,它包含了内嵌的组件model,如果卡片没有body,即没有组件,也就不在视觉上做渲染。卡片的布局也就是对body里包含的组件来进行布局。Tangram内置了一系列布局能力对组件进行布局,包括流式布局、瀑布流布局、吸顶布局、悬浮布局、轮播布局等等,基本上常见的布局方式都可以覆盖到。header、footer是卡片的标题和尾部,这是根据业务场景设计的可选内容,因为很多时候一块业务区域会有个标题之类的东西。在实现的时候,我们可以将他们转换到body里的组件,但在概念上,单独描述会更容易理解。style是对布局样式的描述,所有布局会有一些通用的样式属性,也有一些特有的,通过样式的描述,可以让布局能力更加丰富。画图举几个例子:

举个例子

3.4 卡片样式简介

卡片样式

这里对卡片的样式做一些介绍,因为很多时候页面调整就是对样式的调整,结构调整也会涉及到样式调整,因此样式的动态性对页面的动态性具有重要贡献,这里举例的是几个通用的样式属性,如果卡片比较特殊,还可以自定义样式属性。

  • backgroundColor: 卡片的背景,在做页面氛围的时候经常会用到。
  • margin/padding: 卡片外边距、内边距,这是通用UI系统都会支持的属性。
  • gap: 卡片内的组件往往需要增加间距,如果通过组件的margin来实现,会有很多不便之处,相邻组件间左右或者上下都配置了margin,则需要考虑去重的实现,要么就在配置的时候对相邻组件的margin做精心控制。用gap的概念则很方便,它可以指定水平方向间距、垂直方向间距。
  • cols: 默认情况下,流式布局每一列宽度都是等分屏幕宽度的,如果需要做不等分的布局,就可以通过cols来指定每一列的占比,这样布局能力就能更加丰富了。

3.5 组件模型

组件模型

组件的职责是负责业务逻辑和UI元素展示,它是尽可能小的业务单元,一般以实际设计稿出发,抽象出最小可复用单元。组件也是声明式的,需要在model的数据里描述组件的类型,至于有哪些类型,也是业务方在接入时预先注册,因为组件的业务成分比较重,Tangram一般就不内置了。除了类型描述,model数据里剩下的就是组件的数据和样式描述了。组件的数据不做具体规范,一般满足组件自身的需求即可,样式也不做强制规范,但有一些和布局相关的样式在框架层面会进行支持,这个下文介绍。

在组件的实现上,它首先是一个普通的View,并特殊之处,如果脱离Tangram框架,它也应该能正常运行使用。但在Tangram里,我们为组件设计了一个统一的ViewModel,定义了几个生命周期事件;通过ViewModel对组件的属性进行赋值,在组件初始化时会调用init,在滑入屏幕绑定数据时候调用bind,在滑出屏幕解除绑定时调用unbind。

除此之外组件的行为基本上都是业务逻辑了,不做过多介绍,这里再介绍几个和页面动态性相关的样式。

3.6 组件样式简介

组件样式

  • backgroundColor: 组件的背景,同样也是在做页面氛围的时候经常会用到。
  • margin/padding: 组件外边距、内边距,同样也是UI系统都会支持的属性。
  • display: 参考css的设计,特别是在流式布局里,组件默认都是内联(inline)的,当布局占满屏幕宽度时,再考虑换行。如果在正常的流式卡片布局里要横插一行,则可以将组件声明为block,不然的化,就得将这个卡片打散成三个卡片才行。
  • colspan: 默认情况下,流式布局每一列宽度都是等分屏幕宽度的,也就是占用一个格子,组件上声明colspan可以让这个组件占用多个格子。它与卡片上的cols区别在于它占用的宽度值是离散的,而cols通过百分比可以做到宽度值的连续分布。
  • width/height: 其实是组件的宽高比,用来对组件进行对齐,利于界面排版。

每个组件都可以声明额外的自定义样式属性,比如字体颜色、字体大小等等,这里就不做过多介绍。通过卡片和组件的样式,基本上就可以组合出大部分场景的页面结构了,也就是Tangram的初衷——像搭积木一样拼装一个页面。

4. 实现原理

上面介绍了整个Tangram的基本概念,花了这么多篇幅讲概念模型,除了告诉大家这个东西是什么、它做什么、它是怎么设计的,最重要传递的一个信息是,作为业务系统,需要首先在概念模型上做好架构设计,在协议规范上做好统一,这样具体的平台去实现的时候,都能根据这个规范来做实现,不管谁实现的,都属于Tangram,这就好比JAVA虚拟机规范和JAVA虚拟机的关系一样。对于我们团队来说,对Tangram的实现也经历了一系列变更,但基本规范没怎么变动,这也是能大规模去支持业务的一个重要支点。下面会介绍目前实现上的思路和重要技术点。

4.1 基本结构和流程

基本流程

主要有这么几个组成:核心引擎、数据解析器、卡片库、组件库、布局框架,核心引擎负责调度整个流程,在启动框架的时候要核心引擎要做一系列初始化,包括初始化卡片库和组件库,也就将内置的卡片类型注册进框架,将外部业务提供的组件也注册好,同时也要将数据解析器初始化好,布局框架也要初始化好。当页面数据传入的时候,核心引擎调用数据解析器将数据转换成卡片和组件的model对象,解析过程会根据之前注册过的卡片、组件类型来解析,不认识的数据将会被抛弃,卡片和组件的基本样式也会解析。解析完毕的卡片、组件model将会扔给布局框架进行页面渲染。布局框架根据卡片提供的布局信息进行布局,根据组件提供的组件信息进一步获取组件实例,贴到布局容器里。

4.2 布局框架实现

核心点

实现上难度最大的在于布局框架,布局框架的灵活性、性能决定了整个Tangram的灵活性和性能。在Android上,布局框架基于RecyclerView+自定义LayoutManager的方式实现;在iOS上,布局框架基于自定义的LazyScrollView来实现。这两框架基本上都能做到对页面的扁平化实现,提供了夸卡片的组件级别复用能力。先对这两块做一个介绍:

RecyclerView

整个页面树被解析出卡片+组件的数据列表之后,会对块数据做进一步转换。首先提取所有组件model,也就是将组件都打平到同一级别的列表,这个列表会被传递给RecyclerViewAdapter,因此数据的位置其实就对应了RecyclerView看到的组件位置。而卡片model,将会拿来构建一个个LayoutHelper,这些LayoutHelper是负责具体布局的对象,一种布局类型的卡片对应于一种LayoutHelper,而且LayoutHelper还包含了它负责的组件的位置起始区域,它们会被传递给自定义的LayoutManager。当RecyclerView开始渲染页面或者滑动时,它内部维护了一个布局状态,获取当前屏幕范围内还有多少区域是空白的,下一个要加载的View的位置是多少,然后把这些信息告诉LayoutManager去加载View做布局。我们的自定义LayoutManager拿到这个位置之后,就反向查找对应的LayoutHelper,然后交给LayoutHelper去布局,这个过程还会涉及到从回收复用池或者通过Adapter获取一个组件实例。不同的LayoutHelper会按照约定的协议进行进一步布局。

LazyScrollView

对于iOS来说,也有类似的布局逻辑,但这里重点介绍iOS的页面容器LazyScrollView。这是一个自定义的滚动布局,具备回收复用能力。它的回收复用算法是这样的:在页面渲染前先计算所有组件的位置信息,根据组件在页面内位置的上边距做一个排序索引,根据下边距再做一个排序索引。页面滚动的时候通过滚动区域与上下边距的取交集,就可以获取到当前可见范围的组件是哪些,然后不可见范围内的组件实例可以回收,新进入可视区域的组件可以从回收复用池里拿到组件实例或者新创建一个组件实例贴到布局里。

4.3 扩展

上面介绍的内容构建里Tangram的基本骨架,但要支撑起业务,还需要很多辅助工具,如果没有这些扩展,将很难支撑业务。这些扩展有些是内部注册在框架,也有些是外部注入。

扩展

  • 点击处理模块,组件都需要有点击交互,点击处理模块定义了接口,业务方根据接口实现具体模块然后注入。
  • 曝光处理模块,与点击模块类似,可提供组件曝光时的业务逻辑加载。
  • 通用定时器模块,用来提供计时功能,满足组件内的倒计时需求、定时需求。
  • 事件总线,用来做组件与卡片的通信,或者组件与外部通信等等。
  • 脚本动画,将动画脚本画,提供动画的动态能力,让组件的交互更加丰富。
  • 通用请求模块,有时候卡片数据、或者组件数据需要调用远程接口更新,同通用请求也是定义了加载接口,外部业务方自行实现注入。
  • 纯动态组件,解决组件动态问题,因为我们的动态化是粗粒度的,行走江湖免不了内置动态能力满足不了一个临时需求的场景。动态组件集成了集团内的动态化方案,目前最主要的就是阿里的Weex方案,通过Weex的动态能力来解决组件的动态能力。

有了这些扩展功能,整个Tangram落地到业务就非常方便了,目前我们支撑了天猫首页、天猫直播首页、天猫超市首页等重要业务,还推广到了集团其他部门。

5. 实践经验

最后分享一些业务开发的经验,分客户端和后端运营两方面介绍。延伸到其他业务,这些经验应该也是有借鉴意义的。

5.1 客户端

客户端经验

首先是规范与协议的统一,我们这个框架支撑了多个业务,不同业务、不同平台之间,只有规范统一,才能尽可能支撑多的业务,否则不同业务接入,要做转换,是一件成本很高的事情。在不同平台之间统一规范,也可以让一份数据在多端使用。

在客户端上开发,稳定性是一个非常重要的指标,整个应用应该有自己的保护模式,对于框架来说,我们也要有防御性编程的思维,特别是是动态化方案,往往根据数据来执行代码,访问数据本身要足够小心,像空字段、类型转换、数组越界都是场景的问题,通过安全方法的使用,可以在一个地方保证数据访问的安全性。

组件库,也是一个非常重要的建设,不同业务之间可以复用相同的组件,减少组件开发。

容器化是实现页面在线拼装的一个必要的建设,客户端需要有一个容器页面,就像webview一样,给一个url,就可以加载页面,后端也也需要做数据的容器化接入,能导入业务数据,按照Tangram协议输出。再利用组件库里的现有组件,就可以完成一个页面搭建,目前有一些简单的页面(搜索专辑、推荐专辑)就是这样完成上线的。

解耦也是一个老生常谈的问题,在Tangram里实现扩展能力的时候,解耦这一方面做得就特别棒,像脚本动画、Weex都是其他团队的成果,但是可以很方便的插入到Tangram框架里,而且可以热插拔,业务方不想使用就可以不接入。

5.2 运营管理

运营管理

Tangram是一个动态框架,虽然它的重点技术在客户端,但是没有后端的话是不完整的,必须要有一个完善的后端管理平台来做页面的日常运维才行。我们开发了一个专门的管理后台,可以对Tangram页面做多维度的管理。后端管理平台还承载了页面的稳定性、页面发布的效率、页面试错等能力。

Tangram页面动态调整都是配置发布,视觉调整。因此我们有独特的发布流程,首先后台变更完成之后不会直接发布,而是进入到预发布状态,在这个状态下,可以通过白名单预览提前检查变更效果,预览的方式是将变更生成一个二维码,在手机上扫码预览,检查最真实的效果。通过时间机器调整时间,不仅可以预览这次变更在当前时间的效果,还可以预览将来某个时间的效果,因为不同的时间点,生效的数据不一样,因此时间维度的预览特别有用。另外管理平台对变更人员也做了权限控制,每个业务方人员只能变更自己负责的业务,不会改动到其他业务的页面,通过对接流程平台,让每次变更都有记录可查,防止线上数据随意更改。

有了页面发布、变更的稳定性保证,发布的效率也是下一个重要考虑的问题。定时发布可以让变更在指定时间生效,比如双十一的时候很多东西要0点生效,如果0点做变更、预览、再上线,风险很大,有了定时发布,可以提前做好准备。一键下线的功能,可以做多版本里的某个共用卡片批量下线,特别是紧急情况。批量复制创建卡片和版本通配,都是为了解决新版本发布时候的效率,目前我们针对一个版本客户端就发布一份页面配置数据,有了版本通配,可以减少页面配置的数量,有了批量复制创建,可以在要创建新版本页面的时候复制页面。

快速试错,这是近年来非常热门的一个领域,当页面要进行调整的时候,我们希望看到调整的效果,这个时候abtest就派上了用场。天猫有一套自己的试错平台,Tangram前后端都对接了这条试错平台,在管理平台可以将变更做成实验变更,然后导入到试错平台下发到客户端,进入到实验分桶的用户就可以访问到实验变更,同时试验平台在端上也做了数据采集,这样可以在小范围内先试验变更的效果,根据数据来做接下来的决策。

6. 小结

本次分享整体性的介绍了Tangram的技术方案和一些开发经验,内容比较多,很多地方只能在整体思路上进行介绍,后续我们会逐步将一些细节开放出来分享。本文提到的一些天猫相关技术在团队博客上有介绍,欢迎访问:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

苹果核 - 页面动态化的基础 —— Tangram 的相关文章

  • 学会Mybatis框架:一文掌握MyBatis与GitHub插件分页的完美结合【三.分页】

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 Welcome Huihui s Code World 一 Mybatis分页 1 Mybatis自带分页 2 插件分页 二
  • Jsf与Spring的整合原理

    Jsf做为Web框架 Spring做为业务层框架 两者可以结合起来用 只要在faces config xml中做一个很简单的配置
  • webservice中JAX-WS与CXF,Axis区别

    Web Service是一种能够使应用程序在不同的平台使用不同的编程语言进行通讯的技术规范 而这种技术规范的实现可以用不同的方法 比如使用基于XML形式的协议 SOAP 进行通讯或者是RESTFUL形式的 既然我们知道可以使用上面的两种形式
  • 解析WINDOWS中的DLL文件---经典DLL解读

    在Windows世界中 有无数块活动的大陆 它们都有一个共同的名字 动态链接库 现在就走进这些神奇的活动大陆 找出它们隐藏已久的秘密吧 初窥门径 Windows的基石 随便打开一个系统目录 一眼望去就能看到很多扩展名DLL的文件 这些就是经
  • java自学笔记12:java中的集合框架(下)List

    一 学生选课 判断List中课程是否存在 思考 在课程序列中 如何判断是否包含某门或者某几门课程 如果课程序列包含某门课程 如何判断该课程的索引位置 在学生映射表中 如何判断是否包含某个学生ID 又该如何判断是否包含某个学生对象 如果想把课
  • SSM三层架构之间整合

    一 前言 之前学习ssm框架的时候都是每个框架独立分散的系统性学习 对于框架的整体 总结效果不太好 后来看了黑马视频教程有个老师的思路给了我比较大的启发 以spring为中心 去整合springmvc mybatis 无论是搭建环境 还是理
  • 框架--SpringWeb

    文章目录 一 springweb 1 概述 2 springWeb层搭建 3 请求中的地址如何定义 4 如何接收请求中的数据 5 直接使用对象接收 6 post请求中文乱码处理 7 Ajax 返回 JSON 8 跨域问题 9 拦截器 10
  • maven环境变量配置,总不成功,你就这样试试

    我下载了maven 解压后的目录为 配置了用户变量为下图 然后配置系统的path变量如下图 配置完后我也重启了系统 但是还是显示为下图 这是怎么回事 我进入 bin 下执行命令就没问题 说明程序好好的 但是这个怎么就是不成功呢 分享到 举报
  • please remember me(auto login)

    记住我 用户自动登录的实现 auto login 一 什么是用户自动登录 对于我们的网站向已注册用户提供某些专门的服务 比如网上购物 在线下载 收费浏览等等 就会要求用户在使用这些服务之前进入登录页面 输入用户名和密码 并进行验证 如果用户
  • SpringCloud 微服务架构

    目前微服务架构还是比较火的 但是 为什么会选择springcloud 作为 微服务架构呢 列如 dubbo Motan 等等技术都是比较多的 但是依然springcloud 占据了很大一部分 值得深思 目录 一 选型依据 二 目前微服务架构
  • 在Maven中前端构建实践

    NodeJS为前端技术的发展带来了一次革新 层出不穷的前端库 框架以及打包工具让大家应接不暇 然而这使得前端技术越来越依赖于NodeJS 基于NodeJS编写的前后台项目可以使用同一编译或者打包工具进行管理从而做到无缝的前后端版本控制以及联
  • SpringMVC:从入门到精通,7篇系列篇带你全面掌握--五.JSR303和拦截器

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于SpringMVC的相关操作吧 目录 Welcome Huihui s Code World 一 JSR303是什么 二 使用JSR303的优势 三 使用JS
  • SpringMVC:从入门到精通,7篇系列篇带你全面掌握--七.自定义注解

    目录 Welcome Huihui s Code World 一 Java注解简介 1 原生注解的分类 1 JDK基本注解 Override SuppressWarnings value unchecked 2 JDK元注解 Retenti
  • 如何设计一个麻雀般的微型分布式架构?

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由mariolu 发表于云 社区专栏 序言 初衷 设计该系统初衷是基于描绘业务 或机器集群 存储模型 分析代理缓存服务器磁盘存储与回源率的关系 系统意义是在腾讯云成本优化过程中
  • Android MVP 详解(上)

    作者 李旺成 时间 2016年4月3日 Android MVP 详解 下 已经发布 欢迎大家提建议 MVP 在 Android 上的使用其实已经有挺长一段时间了 长到似乎有点 过时 了 目前风头正劲的是MVVM 那为什么现在还要讲 MVP
  • Weex 介绍

    文章目录 一丶Weex的介绍 二丶前置知识 三丶适用人群 四丶Weex的优势 五丶难点 六丶Weex ReactNative Flutter的区别 七丶设计理念 八丶基本原理 九丶有谁在用 十丶Weex调试工具 十一丶构建一个最简单的应用
  • 从0开始写Vue项目-Vue页面主体布局和登录、注册页面

    1 从0开始写Vue项目 环境和项目搭建 慕言要努力的博客 CSDN博客 2 从0开始写Vue项目 Vue2集成Element ui和后台主体框架搭建 慕言要努力的博客 CSDN博客 一 主体布局 关于主体布局 我们刚开始肯定是做的死数据的
  • 值得一看的WinPhone入门系列文章

    今天发现了一些Windows Phone开发入门的系列文章 很适合初学者 下面把其连接总结如下 1 概论 http www winphonecoder com forum php mod viewthread tid 185 extra p
  • SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询

    摘要 本文我们将继续分享介绍Spring Boot在整合Mybatis开发企业级应用时其他典型的业务场景 即Mybatis是如何实现多表关联查询时将查询结果集与对象进行映射的 主要的内容包含 一对一的表关联 和 一对多 多对多的表关联 查询
  • 10分钟带你了解轻量级插件框架x3py

    写在前面 由于本人目前主要从事的是Windows客户端开发方面的工作 所以本文介绍x3py的侧重点也是从客户端程序开发者方面叙述的 本文主要参考整理自x3py的官方Wiki 修正了一些官方示例中的错误 有兴趣的同学可以直接阅读原文 设计目的

随机推荐

  • python最常用的几个模块大全,你都掌握了吗?

    一 os模块 1 os remove 删除文件 2 os rename 重命名文件 3 os unlink 删除文件 4 os listdir 列出指定目录下所有文件 5 os getcwd 获取当前文件路径 6 os mkdir 新建目录
  • pip install 使用国内镜像

    https blog csdn net dss875914213 article details 86500146
  • Mysql搭建以及使用

    优势 1 运行速度快 体积小 命令执行的速度快 2 使用成本低 mysql 是开源的 且提供免费版本 3 使用容易 与其他大型数据库的设置和管理相比 其复杂程度较低 易于使用 4 可移植性强 能够运行与多种系统平台上 如windouws L
  • 完整HTML实例网页代码(4)

    上接完整HTML实例网页代码 3 的js格式代码 3 gt 新建一个名为swiper min js的动画格式文件 代码 Swiper 4 5 0 Most modern mobile touch slider and framework w
  • Python 3.11,新特性亮点满满,让你的编程之路更加轻松!

    Python 3 11 已经发布了 这个版本中有很多令人兴奋的新特性 让 Python 开发者们的工作更加简单 高效和有趣 在本篇博客中 我们将介绍 Python 3 11 的五个最新特性 并提供示例来演示如何使用它们 1 模式匹配 简介
  • 添加layer的方法

    this gameObject layer LayerMask NameToLayer KongLong 为何这些脚本前边的方框都不见了 是因为这些脚本中没有Start 或者Update FixedUpdate OnGUI 等等方法 测试添
  • 【流媒体协议】RTMP和RTSP的区别

    RTMP和RTSP都是常用的流媒体协议 支持推流和拉流 但是它们的特点不同 应用场景也不同 RTMP协议 全称Real Time Messaging Protocol RTMP将整个视频分割为多个小的片段进行传输 基于TCP 连接稳定 低延
  • Java基础--------网络编程

    参考http www cnblogs com xdp gacl p 3631965 html 点击打开链接 以此为模板 自己做了整理 修改 目录 一 网络的概念 二 网络通信协议及接口 2 1 通信协议分层思想 2 2 参考模型 三 IP
  • AD怎么设置相同网络的线宽

    一 对网络进行分类 快捷键 D C 在弹出的面板中找到 net class 单击右键 选择 Add Class 二 选择网络 选中Net Classes中刚刚建好的类POWER 按住CTRL键 在Non Members中选择5V 20V 先
  • 最强nba体验服显示服务器正在停机,最强NBA玩不了怎么办 游戏进不去玩不了原因分析及解决方法...

    对于一些刚下载好游戏的萌新玩家来说 最头疼的可能就是游戏进不去或玩不了了 那么最强NBA玩不了怎么办 不要慌 小编这就给大家分析下游戏玩不了或进不去的各种原因以及解决方法 类别 体育竞技 大小 471 34M 语言 简体中文 评分 10 最
  • golang for range循环坑

    比较两段代码 package main import fmt func main a int 1 2 3 4 5 6 7 8 9 for len a gt 0 a a 1 fmt Println a 输出 2 3 4 5 6 7 8 9 3
  • 分布式概念

    集群与分布式区别 集群 复制模式 每台机器做一样的事 分布式 两台机器分工合作 每台机器做的不一样 分布式好处 独立开发 部署 测试 易于扩展 复用性高 例如 所有的产品都可以使用该系统作为用户系统 无需重复开发 架构演进 架构演进一 早期
  • python 如何查看模块所有方法-Python查看模块(变量、函数、类)方法

    常用五种方法 前提是要先导入这个包 然后用下面的方法去查看 这名称 可是包 方法 或 类 1 help 名称 2 名称 doc 3 dir 模块名 List item 通过 dir 函数获取到的模块成员 不仅包含供外部文件使用的成员 还包含
  • PySide6/PyQT多线程之 高效管理多线程:暂停、恢复和停止的最佳实践

    前言 关于 PySide6 PyQT 多线程 正确地处理多线程编程并确保线程之间的同步和通信并不容易 本文以一个示例代码为基础 介绍 PySide6 PyQT多线程的运用 展示如何创建和管理线程 以及如何实现线程之间的同步和通信 设想这么一
  • python 切换root 执行命令

    如下 以创建系统用户举例 配置文件配置普通用户信息 登入后切换root用户 创建一个指定名字和密码的系统用户 def create user root pwd username password import paramiko result
  • STM32 RST管脚上拉后一直是0.1V左右的低电平,恶心,终于找到原因,焊锡膏啊

    给自己以后提醒 这次做的STM32平衡车的板子 发现仿真器一直烧写不进去 提示 core is held 先看魔术棒 排除了仿真器连接的问题 上网搜 core is held 原因 网友说应该是复位脚RST的电平没有拉高 但是我的原理图上已
  • 原码、反码、补码基本概念

    基本概念 原码 符号位加上真值的绝对值 也就是第一位表示符号 其余位表示值 0为正值 1为负值 原码是人脑最容易理解和计算的表示方式 反码 正数的反码是其本身 负数的反码是在其原码的基础上符号位不变 其余各位取反 一个反码表示的负数是无法无
  • Golang学习笔记:递归函数

    接前面java写的递归例子 还是计算一个数递减相乘 func test01 n int int result 0 if n lt 1 return 1 else result test01 n 1 n return result 执行一个函
  • IDEA个性化设置注释模板(详细版)

    IDEA设置注释模板 类注释模板 方法注释模板 效果展示 1 类注释模板 类注释模板是IDEA创建类时生成的注释 第一步 File gt Settings 第二步 Editor gt File and Code Templates gt I
  • 苹果核 - 页面动态化的基础 —— Tangram

    12月10日在SFDC SegmentFault Developer Conference 大会上初次介绍了手机天猫的Tangram方案 现场时间有限 讲得匆忙 特此整理记录 这篇内容是Tangram的整体介绍与相关业务开发实践的介绍 后续