当前位置: 首页 > 编程日记 > 正文

读Zepto源码之操作DOM

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

这篇依然是跟 dom 相关的方法,侧重点是操作 dom 的方法。

读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto

源码版本

本文阅读的源码为 zepto1.2.0

.remove()

remove: function() {return this.each(function() {if (this.parentNode != null)this.parentNode.removeChild(this)})
},

删除当前集合中的元素。

如果父节点存在时,则用父节点的 removeChild 方法来删掉当前的元素。

相似方法生成器

zeptoafterprependbeforeappendinsertAfterinsertBeforeappendToprependTo 都是通过这个相似方法生成器生成的。

定义容器

adjacencyOperators = ['after', 'prepend', 'before', 'append']

首先,定义了一个相似操作的数组,注意数组里面只有 afterprependbeforeappend 这几个方法名,后面会看到,在生成这几个方法后,insertAfterinsertBeforeappendToprependTo 会分别调用前面生成的几个方法。

辅助方法traverseNode

function traverseNode(node, fun) {fun(node)for (var i = 0, len = node.childNodes.length; i < len; i++)traverseNode(node.childNodes[i], fun)
}

这个方法递归遍历 node 的子节点,将节点交由回调函数 fun 处理。这个辅助方法在后面会用到。

核心源码

adjacencyOperators.forEach(function(operator, operatorIndex) {var inside = operatorIndex % 2 //=> prepend, append$.fn[operator] = function() {// arguments can be nodes, arrays of nodes, Zepto objects and HTML stringsvar argType, nodes = $.map(arguments, function(arg) {var arr = []argType = type(arg)if (argType == "array") {arg.forEach(function(el) {if (el.nodeType !== undefined) return arr.push(el)else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())arr = arr.concat(zepto.fragment(el))})return arr}return argType == "object" || arg == null ?arg : zepto.fragment(arg)}),parent, copyByClone = this.length > 1if (nodes.length < 1) return thisreturn this.each(function(_, target) {parent = inside ? target : target.parentNode// convert all methods to a "before" operationtarget = operatorIndex == 0 ? target.nextSibling :operatorIndex == 1 ? target.firstChild :operatorIndex == 2 ? target :nullvar parentInDocument = $.contains(document.documentElement, parent)nodes.forEach(function(node) {if (copyByClone) node = node.cloneNode(true)else if (!parent) return $(node).remove()parent.insertBefore(node, target)if (parentInDocument) traverseNode(node, function(el) {if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&(!el.type || el.type === 'text/javascript') && !el.src) {var target = el.ownerDocument ? el.ownerDocument.defaultView : windowtarget['eval'].call(target, el.innerHTML)}})})})}

调用方式

在分析之前,先看看这几个方法的用法:

after(content)
prepend(content)
before(content)
append(content)

参数 content 可以为 html 字符串,dom 节点,或者节点组成的数组。after 是在每个集合元素后插入 contentbefore 正好相反,在每个集合元素前插入 contentprepend 是在每个集合元素的初始位置插入 contentappend 是在每个集合元素的末尾插入 contentbeforeafter 插入的 content 在元素的外部,而 prependappend 插入的 content 在元素的内部,这是需要注意的。

将参数 content 转换成 node 节点数组

var inside = operatorIndex % 2 //=> prepend, append

遍历 adjacencyOperators,得到对应的方法名 operator 和方法名在数组中的索引 operatorIndex

定义了一个 inside 变量,当 operatorIndex 为偶数时,inside 的值为 true,也就是 operator 的值为 prependappend 时,inside 的值为 true 。这个可以用来区分 content 是插入到元素内部还是外部的方法。

$.fn[operator] 即为 $.fn 对象设置对应的属性值(方法名)。

var argType, nodes = $.map(arguments, function(arg) {var arr = []argType = type(arg)if (argType == "array") {arg.forEach(function(el) {if (el.nodeType !== undefined) return arr.push(el)else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())arr = arr.concat(zepto.fragment(el))})return arr}return argType == "object" || arg == null ?arg : zepto.fragment(arg)
}),

变量 argType 用来保存变量变量的类型,也即 content 的类型。nodes 是根据 content 转换后的 node 节点数组。

这里用了 $.map arguments 的方式来获取参数 content ,这里只有一个参数,这什么不用 arguments[0] 来获取呢?这是因为 $.map 可以将数组进行展平,具体的实现看这里《读zepto源码之工具函数》。

首先用内部函数 type 来获取参数的类型,关于 type 的实现,在《读Zepto源码之内部方法》 已经作过分析。

如果参数 content ,也即 arg 的类型为数组时,遍历 arg ,如果数组中的元素存在 nodeType 属性,则断定为 node 节点,就将其 push 进容器 arr 中;如果数组中的元素为 zepto 对象(用 $.zepto.isZ 判断,该方法已经在《读Zepto源码之神奇的$》有过分析),不传参调用 get 方法,返回的是一个数组,然后调用数组的 concat 方法合并数组,get 方法在《读Zepto源码之集合操作》有过分析;否则,为 html 字符串,调用 zepto.fragment 处理,并将返回的数组合并,``zepto.fragment` 在《读Zepto源码之神奇的$》中有过分析。

如果参数类型为 object (即为 zepto 对象)或者 null ,则直接返回。

否则为 html 字符串,调用 zepto.fragment 处理。

parent, copyByClone = this.length > 1
if (nodes.length < 1) return this

这里还定义了 parent 变量,用来保存 content 插入的父节点;当集合中元素的数量大于 1 时,变量 copyByClone 的值为 true ,这个变量的作用后面再说。

如果 nodes 的数量比 1 小,也即需要插入的节点为空时,不再作后续的处理,返回 this ,以便可以进行链式操作。

insertBefore 来模拟所有操作

return this.each(function(_, target) {parent = inside ? target : target.parentNode// convert all methods to a "before" operationtarget = operatorIndex == 0 ? target.nextSibling :operatorIndex == 1 ? target.firstChild :operatorIndex == 2 ? target :nullvar parentInDocument = $.contains(document.documentElement, parent)...
})

对集合进行 each 遍历

parent = inside ? target : target.parentNode

如果 node 节点需要插入目标元素 target 的内部,则 parent 设置为目标元素 target,否则设置为当前元素的父元素。

target = operatorIndex == 0 ? target.nextSibling :operatorIndex == 1 ? target.firstChild :operatorIndex == 2 ? target :null

这段是将所有的操作都用 dom 原生方法 insertBefore 来模拟。 如果 operatorIndex == 0 即为 after 时,node 节点应该插入到目标元素 target 的后面,即 target 的下一个兄弟元素的前面;当 operatorIndex == 1 即为 prepend 时,node 节点应该插入到目标元素的开头,即 target 的第一个子元素的前面;当 operatorIndex == 2 即为 before 时,insertBefore 刚好与之对应,即为元素本身。当 insertBefore 的第二个参数为 null 时,insertBefore 会将 node 插入到子节点的末尾,刚好与 append 对应。具体见文档:Node.insertBefore()

var parentInDocument = $.contains(document.documentElement, parent)

调用 $.contains 方法,检测父节点 parent 是否在 document 中。$.contains 方法在《读zepto源码之工具函数》中已有过分析。

node 节点数组插入到元素中

nodes.forEach(function(node) {if (copyByClone) node = node.cloneNode(true)else if (!parent) return $(node).remove()parent.insertBefore(node, target)...
})

如果需要复制节点时(即集合元素的数量大于 1 时),用 node 节点方法 cloneNode 来复制节点,参数 true 表示要将节点的子节点和属性等信息也一起复制。为什么集合元素大于 1 时需要复制节点呢?因为 insertBefore 插入的是节点的引用,对集合中所有元素的遍历操作,如果不克隆节点,每个元素所插入的引用都是一样的,最后只会将节点插入到最后一个元素中。

如果父节点不存在,则将 node 删除,不再进行后续操作。

将节点用 insertBefore 方法插入到元素中。

处理 script 标签内的脚本

if (parentInDocument) traverseNode(node, function(el) {if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&(!el.type || el.type === 'text/javascript') && !el.src) {var target = el.ownerDocument ? el.ownerDocument.defaultView : windowtarget['eval'].call(target, el.innerHTML)}
})

如果父元素在 document 内,则调用 traverseNode 来处理 node 节点及 node 节点的所有子节点。主要是检测 node 节点或其子节点是否为不指向外部脚本的 script 标签。

el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT'

这段用来判断是否为 script 标签,通过 nodenodeName 属性是否为 script 来判断。

!el.type || el.type === 'text/javascript'

不存在 type 属性,或者 type 属性为 'text/javascript'。这里表示只处理 javascript,因为 type 属性不一定指定为 text/javascript ,只有指定为 test/javascript 或者为空时,才会按照 javascript 来处理。见MDN文档script

!el.src

并且不存在外部脚本。

var target = el.ownerDocument ? el.ownerDocument.defaultView : window

是否存在 ownerDocument 属性,ownerDocument 返回的是元素的根节点,也即 document 对象,document 对象的 defaultView 属性返回的是 document 对象所关联的 window 对象,这里主要是处理 iframe 里的 script,因为在 iframe 中有独立的 window 对象。如果不存在该属性,则默认使用当前的 window 对象。

target['eval'].call(target, el.innerHTML)

最后调用 windoweval 方法,执行 script 中的脚本,脚本用 el.innerHTML 取得。

为什么要对 script 元素单独进行这样的处理呢?因为出于安全的考虑,脚本通过 insertBefore 的方法插入到 dom 中时,是不会执行脚本的,所以需要使用 eval 来进行处理。

生成 insertAfterprependToinsertBeforeappendTo 方法

先来看看这几个方法的调用方式

insertAfter(target)
insertBefore(target)
appendTo(target)
prependTo(target)

这几个方法都是将集合中的元素插入到目标元素 target 中,跟 afterbeforeappendprepend 刚好是相反的操作。

他们的对应关系如下:

after    => insertAfter
prepend  => prependTo
before   => insertBefore
append   => appendTo

因此可以调用相应的方法来生成这些方法。

$.fn[inside ? operator + 'To' : 'insert' + (operatorIndex ? 'Before' : 'After')] = function(html) {$(html)[operator](this)return this
}
inside ? operator + 'To' : 'insert' + (operatorIndex ? 'Before' : 'After')

这段其实是生成方法名,如果是 prependappend ,则在后面拼接 To ,如果是 BeforeAfter,则在前面拼接 insert

$(html)[operator](this)

简单地反向调用对应的方法,就可以了。

到此,这个相似方法生成器生成了afterprependbeforeappendinsertAfterinsertBeforeappendToprependTo 等八个方法,相当高效。

.empty()

empty: function() {return this.each(function() { this.innerHTML = '' })
},

empty 的作用是将所有集合元素的内容清空,调用的是 nodeinnerHTML 属性设置为空。

.replaceWith()

replaceWith: function(newContent) {return this.before(newContent).remove()
},

将所有集合元素替换为指定的内容 newContentnewContent 的类型跟 before 的参数类型一样。

replaceWidth 首先调用 beforenewContent 插入到对应元素的前面,再将元素删除,这样就达到了替换的上的。

.wrapAll()

wrapAll: function(structure) {if (this[0]) {$(this[0]).before(structure = $(structure))var children// drill down to the inmost elementwhile ((children = structure.children()).length) structure = children.first()$(structure).append(this)}return this
},

将集合中所有的元素都包裹进指定的结构 structure 中。

如果集合元素存在,即 this[0] 存在,则进行后续操作,否则返回 this ,以进行链式操作。

调用 before 方法,将指定结构插入到第一个集合元素的前面,也即所有集合元素的前面

while ((children = structure.children()).length) structure = children.first()

查找 structure 的子元素,如果子元素存在,则将 structure 赋值为 structure 的第一个子元素,直找到 structrue 最深层的第一个子元素为止。

将集合中所有的元素都插入到 structure 的末尾,如果 structure 存在子元素,则插入到最深层的第一个子元素的末尾。这样就将集合中的所有元素都包裹到 structure 内了。

.wrap()

wrap: function(structure) {var func = isFunction(structure)if (this[0] && !func)var dom = $(structure).get(0),clone = dom.parentNode || this.length > 1return this.each(function(index) {$(this).wrapAll(func ? structure.call(this, index) :clone ? dom.cloneNode(true) : dom)})
},

为集合中每个元素都包裹上指定的结构 structurestructure 可以为单独元素或者嵌套元素,也可以为 html 元素或者 dom 节点,还可以为回调函数,回调函数接收当前元素和当前元素在集合中的索引两个参数,返回符合条件的包裹结构。

var func = isFunction(structure)

判断 structure 是否为函数

if (this[0] && !func)var dom = $(structure).get(0),clone = dom.parentNode || this.length > 1

如果集合不为空,并且 structure 不为函数,则将 structure 转换为 node 节点,通过 $(structure).get(0) 来转换,并赋给变量 dom。如果 domparentNode 存在或者集合的数量大于 1 ,则 clone 的值为 true

return this.each(function(index) {$(this).wrapAll(func ? structure.call(this, index) :clone ? dom.cloneNode(true) : dom)
})

对集合进行遍历,调用 wrapAll 方法,如果 structure 为函数,则将回调函数返回的结果作为参数传给 wrapAll

否则,如果 clonetrue ,则将 dom 也即包裹元素的副本传给 wrapAll ,否则直接将 dom 传给 wrapAll。这里传递副本的的原因跟生成器中的一样,也是避免对 dom 节点的引用。如果 domparentNode 存在时,表明 dom 本来就从属于某个节点,如果直接使用 dom ,会破坏原来的结构。

.wrapInner()

wrapInner: function(structure) {var func = isFunction(structure)return this.each(function(index) {var self = $(this),contents = self.contents(),dom = func ? structure.call(this, index) : structurecontents.length ? contents.wrapAll(dom) : self.append(dom)})
},

将集合中每个元素的内容都用指定的结构 structure 包裹。 structure 的参数类型跟 wrap 一样。

对集合进行遍历,调用 contents 方法,获取元素的内容,contents 方法在《读Zepto源码之集合元素查找》有过分析。

如果 structure 为函数,则将函数返回的结果赋值给 dom ,否则将直接将 structure 赋值给 dom

如果 contents.length 存在,即元素不为空元素,调用 wrapAll 方法,将元素的内容包裹在 dom 中;如果为空元素,则直接将 dom 插入到元素的末尾,也实现了将 dom 包裹在元素的内部了。

.unwrap()

unwrap: function() {this.parent().each(function() {$(this).replaceWith($(this).children())})return this
},

当集合中的所有元素的包裹层去掉,也即将父元素去掉,但是保留父元素的子元素。

实现的方法也很简单,就是遍历当前元素的父元素,将父元素替换为父元素的子元素。

.clone()

clone: function() {return this.map(function() { return this.cloneNode(true) })
},

每集合中每个元素都创建一个副本,并将副本集合返回。

遍历元素集合,调用 node 的原生方法 cloneNode 创建副本。要注意,cloneNode 不会将元素原来的数据和事件处理程序复制到副本中。

系列文章

  1. 读Zepto源码之代码结构
  2. 读 Zepto 源码之内部方法
  3. 读Zepto源码之工具函数
  4. 读Zepto源码之神奇的$
  5. 读Zepto源码之集合操作
  6. 读Zepto源码之集合元素查找

参考

  • Node.insertBefore()
  • Node.cloneNode()
  • Zepto源码分析-zepto模块
  • MDN文档script
  • Node.ownerDocument
  • Document.defaultView

License

License: CC BY-NC-ND 4.0

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面

转载于:https://my.oschina.net/u/3483091/blog/913979

相关文章:

VSS的每日自动备份

小弟在项目中兼职担当配置管理员&#xff0c;备份VSS的重任当然也得我来扛着&#xff0c;不然兄弟们加班加点的劳动果实可能因为什么天灾人祸一不小心就挂了。以往备份VSS的频率是一月一次&#xff0c;近来受到上面的教导&#xff0c;备份频率较少&#xff0c;需要每日备份。难…

当 AI 闯入法律界,第一步是当律师的得力助手

来源 | HyperAI超神经责编 | 晋兆雨头图 | CSDN 下载自视觉中国长久以来&#xff0c;律师这一职业给大众的印象都是精英、雄辩、高薪&#xff0c;而这份工作背后的艰辛却很少被看到。除了出庭之外&#xff0c;律师们要花费大量时间与经历进行法律资料研究、合同文件审查等。为此…

Ubuntu下添加新分区并设置挂载点

Ubuntu下添加新分区并设置挂载点最近在做Android项目&#xff0c;可是解压根文件系统以后&#xff0c;就报警说硬盘不够。当初设置使用的大小为15G。不过扩展分区还是很方便的。当然首先你得设置添加使用的硬盘大小&#xff0c;这次我一下提高到了30G&#xff0c;看它还报警否。…

2016 只剩最后一个月 你的 技术债务 还清了吗?

一夜醒来&#xff0c;猛然发现&#xff0c;2016 已经只剩最后一个月了&#xff01; 回忆过去的 330 多个日与夜&#xff0c;哪些互联网圈的大事让你瞠目结舌&#xff1f; 也许是 AlphaGo 在堪称人脑游戏巅峰的围棋领域屡战告捷&#xff1b; 也许是 Pokmon Go 称霸大洋彼岸&…

给图片加上带版权的水印

我们在网站上有些时候需要给图片加上带版权的水印&#xff0c;.net的Graphics类可以很轻松的实现这一点。效果图&#xff1a;&#xff08;图片最上端的那行字便是我们加上的版权水印了&#xff09;实现代码&#xff1a; /**//// <summary> /// 生成带版权水印的图片 …

重磅推出开发者计划、App Store,赛灵思普及自适应计算的一大步

得开发者得天下。尤其随着AI技术落地趋势加剧&#xff0c;其中大部分创新来自软件应用&#xff0c;市场对软件开发者有着极大需求。因此&#xff0c;无论是互联网公司还是传统的IT厂商都在尝试将开发者沉淀到自己的平台。 作为FPGA的开创者&#xff0c;赛灵思正在突破主要支持硬…

Web 开发人员必备的随机 JSON 数据生成工具

在 Web 开发中&#xff0c;经常会需要一些测试数据来测试接口或者功能时候正确。JSON Generator 就是这样一款生成随机 JSON 数据的在线工具&#xff0c;Web 开发人员必备&#xff0c;记得收藏和分享啊。 您可能感兴趣的相关文章Verlet-js&#xff1a;超炫的开源 JavaScript 物…

bootstrap解析-栅格系统

.container(布局容器) 屏幕宽1200px以上&#xff08;col-lg&#xff09; 1. 默认width为1170px 2. padding,lefet和right各为15px,所以内容width为1140px;屏幕宽992px以上(col-md) 1. 默认width为970px 2. padding,lefet和right各为15px,所以内容width为940px;屏幕宽768px以上(…

asp.net中窗口相关操作总结(javascript)

1.打开新窗口 这个简单:Response.Write("<script language javascript>window.open(url);</script>"); 2.关闭窗口 //关闭当前窗口,并提示用户时候关闭,yes关闭,no退出 Response.Write("<script language javascript>window.close();</sc…

200万注册开发者,13亿张全景图片,90%数据生产环节AI化,百度地图生态全景升级2.0

12月29日&#xff0c; 2020百度地图生态大会在京举办。据介绍&#xff0c;在AI技术加持下&#xff0c;百度地图实现了90%数据生产环节AI化&#xff0c;全新升级生态全景2.0。 百度集团副总裁、百度集团首席信息官(CIO)李莹出席大会并致辞&#xff0c;她表示&#xff1a;“在20…

Sqlite3数据库之第三方库FMDB学习心得

很早之前就接触Sqlite数据库,但是之前对数据库操作未使用任何第三方库,只是实现基本的增、删、改、查功能,自己对着一本iPhone开发入门级的书籍写了一个类,基本能实现上述四个功能。最近在开发一个软件&#xff0c;由于是一个本地应用&#xff0c;经过再三思量&#xff0c;最好…

您会让自己的小孩将来从事软件研发吗?

您会让自己的小孩将来从事软件研发吗&#xff1f;非常多程序猿&#xff0c;都已经30多岁了。过了而立之年&#xff0c;有了自己的老婆&#xff0c;自己温馨的小家庭&#xff0c;自己可爱的小孩。小孩也都是00后的。“您会让自己的孩子从事软件研发吗&#xff1f;”本来小孩的事…

CSDN湘苗培优|成长,从走出舒适区开始

湘苗培优CSDN高校俱乐部报名火热进行中&#xff01;基础训练交付训练实践练习湘苗培优 随着我国信息产业飞速发展&#xff0c;通过常规灌输式培养出来的学员已经不能够满足企业要求。企业更缺乏的是具备自主学习能力、具备综合解决问题能力的高素质技术人才。高素质技术人才需要…

使用VS自带的混淆器防止你的程序被反编译

这里就介绍大家使用VS自带的混淆器dotfuscator.exe来阻止这种行为。首先要做的找到dotfuscator.exe&#xff1a; D:/Microsoft Visual Studio .NET 2003/PreEmptive Solutions/Dotfuscator Community Edition运行dotfuscator.exe首先是是否注册的界面&#xff0c;先不注册吧&am…

【124】排球基本技术

排球基本技术 1.基本技术的概念 是指在规则允许的条件下&#xff0c;运用人体解剖和运动生物力学的原理&#xff0c;所采用的合理击球和完成击球动作的其他配合的总称。 2.排球技术的特点 &#xff08;1&#xff09;完成动作时间短促&#xff1b; &#xff08;2&#xff09;完成…

FairyGUI和NGUI对比

一直在做Unity方面的游戏开发&#xff0c;经同事介绍了解到有这么一个GUI能提供跨平台的能力&#xff0c;有独立UI编辑器&#xff0c;而且功能强大&#xff0c;能够组合成复杂的UI界面&#xff0c;可以导出到Unity,Flash,Starling等&#xff0c;文档还说未来将支持UE4&#xff…

用like语句时的C#格式化函数

*********************************************************************************** * 版权声明 * 此文章为ocean所有&#xff0c;版权归ocean所有&#xff0c;任何网站 *和 媒体转载必须包含此段声明&#xff0c;否则将…

JS-arguments分析

JS-arguments分析waiting……转载于:https://blog.51cto.com/frabbit2013/1242112

200万注册开发者,13亿全景图片,90%数据生产AI化,百度地图如何造生态?

12月29日&#xff0c; 2020百度地图生态大会在京举办。据悉&#xff0c;在AI技术加持下&#xff0c;百度地图实现了90%数据生产环节AI化&#xff0c;并全新升级生态全景2.0。围绕百度地图2020年的各项进展&#xff0c;百度地图总经理季永志做出了全方面回顾&#xff0c;并展示了…

内核中的内存申请:kmalloc、vmalloc、kzalloc、kcalloc、get_free_pages【转】

转自&#xff1a;http://www.cnblogs.com/yfz0/p/5829443.html 在内核模块中申请分配内存需要使用内核中的专用API:kmalloc、vmalloc、kzalloc、kcalloc、get_free_pages;当然,设备驱动程序也不例外;对于提供了MMU功能的处理器而言,Linux提供了复杂的内存管理系统,使得进程所能…

以实例说明如何使用C#从数据库中提取数据,按要求自动生成定制的Excel表格

最近因为需要学习了一下使用C#操作Excel表格&#xff0c;现在把我使用C#如何定制表格的过程提供给需要的兄弟&#xff1a; /*从数据库提取数据*/ string strconn"packet size4096;user idsa;data sourcelocalhost;persist security infoTrue;initial catalogDatabase;pa…

7_7_2013 E.Function

2019独角兽企业重金招聘Python工程师标准>>> Problem E: Function Time Limit: 1 Sec Memory Limit: 32 MB Submit: 52 Solved: 26 [ Submit][ Status][ Web Board] Description Define a function f(n)(f(n-1)1)/f(n-2). You already got f(1) and f(2). Now…

快手日入数据量超 5120TB,数据管治如何做?

​近日&#xff0c;快手大数据团队联合“快手中学”&#xff0c;举办“快手数据管治技术交流会”&#xff0c;各行业数据相关开发者报名参与。在海量的 UGC 数据、业务数据、用户数据背后&#xff0c;支撑快手数据业务的快手大数据平台&#xff0c;秉承“以领先的大数据技术&am…

LINUX创建www的用户组和用户,并且不允许登录权限:

# id www id: www&#xff1a;无此用户 # groupadd www # useradd -g www -s /sbin/nologin www # id www uid501(www) gid501(www) 组501(www) 转载于:https://www.cnblogs.com/cnbing/p/6957239.html

GridView自定义分页导航

自己做的一个项目中所运用到的技术&#xff1a;| 1. 日历控件&#xff08;带时分秒&#xff09;2. GridView 批量删除,自定义分页,定位页码3. GridView 修改4. GridView 鼠标经过改变行的颜色效果如下&#xff1a;HTML&#xff1a;<% Page L…

一文看懂AI数据采集标注未来三年的发展和趋势

影响人工智能发展的三大要素分别是数据、算法、算力&#xff0c;限于篇幅&#xff0c;本篇内容将重点分析未来几年内人工智能所需要的数据趋势及探讨数据服务商发展方向。 作为AI数据采集标注的领先企业&#xff0c;云测数据分析认为人工智能在经历了算法研究、技术扩张和商业落…

HTTP 状态代码及其定义

相关文章&#xff1a;http://ruby-china.org/topics/12384 所有 HTTP 状态代码及其定义。  代码 指示 2xx 成功 200 正常&#xff1b;请求已完成。 201 正常&#xff1b;紧接 POST 命令。 202 正常&#xff1b;已接受用于处理&#xff0c;但处理尚未完成。 203 正常&#xff1…

html5地理定位数据

2019独角兽企业重金招聘Python工程师标准>>> <html><head><meta charset"UTF-8"/> <meta name"viewport" content"widthdevice-width, initial-scale1.0"><script type"text/javascript">fu…

GridView控件修改、删除示例(修改含有DropDownList控件)

GridView控件修改、删除例子&#xff0c;修改时含有DropDownList控件。示例运行效果图&#xff1a;GridViewUp.aspx文件代码&#xff1a; <% Page Language"C#"AutoEventWireup"true"CodeFile"GridViewUp.aspx.cs"Inherits"gridview_Gri…

国产AI芯片加速,鲲云携手浪潮推出数据流AI服务器

近日&#xff0c;鲲云科技携手浪潮基于星空X3加速卡推出新一代的数据流AI服务器&#xff0c;定位高性能图像视频智能分析的AI计算加速&#xff0c;支持智慧城市、智能制造、智慧油田、智慧工地、智算中心等典型AI应用场景&#xff0c;这是双方“元脑生态计划”战略签约后推进的…