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

Knockout.js Virtual Elements 详解

概述

virtualElements.js是 Knockout.js 框架中的一个核心模块,它实现了"虚拟元素"的概念。这个模块解决了在使用容器无关模板(containerless templates)时的 DOM 操作问题,比如 <!-- ko if: someCondition -->...<!-- /ko --> 这样的注释语法。

核心概念

什么是虚拟元素?

虚拟元素是一种抽象概念,它允许使用 HTML 注释节点来表示 DOM 层次结构。传统的 DOM 层次结构由实际的 HTML 元素构成,而虚拟元素扩展了这个概念,允许注释节点也参与层次结构的定义。

容器无关模板

容器无关模板是 Knockout.js 的一个重要特性,它允许我们在不添加额外 DOM 元素的情况下创建绑定。例如:

<!-- ko if: isVisible --><div>Some content</div>
<!-- /ko -->

在这个例子中,<!-- ko if: isVisible --><!-- /ko --> 注释节点定义了一个虚拟容器,中间的内容只有在 isVisible 为 true 时才会显示。

核心实现

注释节点处理

var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->";
var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/;
var endCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;

由于 IE9 的兼容性问题,代码需要处理不同浏览器对注释节点文本内容的访问方式。IE9 使用 text 属性,而其他浏览器使用 nodeValue

虚拟子元素管理

getVirtualChildren 函数

这个函数用于获取虚拟元素的子节点:

function getVirtualChildren(startComment, allowUnbalanced) {var currentNode = startComment;var depth = 1;var children = [];while (currentNode = currentNode.nextSibling) {if (isEndComment(currentNode)) {ko.utils.domData.set(currentNode, matchedEndCommentDataKey, true);depth--;if (depth === 0)return children;}children.push(currentNode);if (isStartComment(currentNode))depth++;}if (!allowUnbalanced)throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);return null;
}

该函数通过跟踪嵌套深度来正确识别虚拟元素的边界,支持嵌套的虚拟元素结构。

主要 API

childNodes
childNodes: function(node) {return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
}

根据节点类型返回子节点:对于虚拟元素起始注释,返回虚拟子节点;对于普通元素,返回实际的 childNodes。

emptyNode
emptyNode: function(node) {if (!isStartComment(node))ko.utils.emptyDomNode(node);else {var virtualChildren = ko.virtualElements.childNodes(node);for (var i = 0, j = virtualChildren.length; i < j; i++)ko.removeNode(virtualChildren[i]);}
}

清空节点内容,对虚拟元素和普通元素分别处理。

setDomNodeChildren
setDomNodeChildren: function(node, childNodes) {if (!isStartComment(node))ko.utils.setDomNodeChildren(node, childNodes);else {ko.virtualElements.emptyNode(node);var endCommentNode = node.nextSibling;for (var i = 0, j = childNodes.length; i < j; i++)endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);}
}

设置节点的子元素,将新子元素插入到结束注释之前。

firstChild 和 nextSibling

这些方法确保在遍历 DOM 时正确处理虚拟元素:

firstChild: function(node) {if (!isStartComment(node)) {if (node.firstChild && isEndComment(node.firstChild)) {throw new Error("Found invalid end comment, as the first child of " + node);}return node.firstChild;} else if (!node.nextSibling || isEndComment(node.nextSibling)) {return null;} else {return node.nextSibling;}
}

特殊处理

IE 兼容性问题处理

代码中特别处理了 IE 浏览器的兼容性问题,包括注释节点的文本属性访问和 DOM 结构解析问题。

HTML 结构规范化

normaliseVirtualElementDomStructure: function(elementVerified) {// Workaround for https://github.com/SteveSanderson/knockout/issues/155// (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes// that are direct descendants of <ul> into the preceding <li>)if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])return;// Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags// must be intended to appear *after* that child, so move them there.var childNode = elementVerified.firstChild;if (childNode) {do {if (childNode.nodeType === 1) {var unbalancedTags = getUnbalancedChildTags(childNode);if (unbalancedTags) {// Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the childvar nodeToInsertBefore = childNode.nextSibling;for (var i = 0; i < unbalancedTags.length; i++) {if (nodeToInsertBefore)elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);elseelementVerified.appendChild(unbalancedTags[i]);}}}} while (childNode = childNode.nextSibling);}
}

此函数处理 IE 浏览器在解析 HTML 时的特殊行为,确保注释节点被正确放置。

使用示例

基本用法

// 获取虚拟元素的子节点
var children = ko.virtualElements.childNodes(startCommentNode);// 清空虚拟元素内容
ko.virtualElements.emptyNode(startCommentNode);// 设置虚拟元素的子节点
ko.virtualElements.setDomNodeChildren(startCommentNode, newChildren);

遍历虚拟元素

var firstChild = ko.virtualElements.firstChild(parentNode);
var nextSibling = ko.virtualElements.nextSibling(currentNode);

总结

[virtualElements.js]是 Knockout.js 实现容器无关模板的关键模块。它通过抽象 DOM 操作,使得框架可以统一处理普通 DOM 元素和虚拟元素,为开发者提供了更灵活的模板编写方式。该模块还充分考虑了各种浏览器的兼容性问题,确保在不同环境下都能正常工作。


文章转载自:

http://IMuiDVyc.bzcpg.cn
http://ft02t1AL.bzcpg.cn
http://KpFOp814.bzcpg.cn
http://9MXHxmSR.bzcpg.cn
http://WOsXuJIh.bzcpg.cn
http://36WhZ21V.bzcpg.cn
http://ADNSbzWd.bzcpg.cn
http://GXGJ9Ujo.bzcpg.cn
http://6O7T4kpE.bzcpg.cn
http://cMXxZB6p.bzcpg.cn
http://WBpNxFKf.bzcpg.cn
http://TnqDnpT5.bzcpg.cn
http://opMGjqiW.bzcpg.cn
http://7wxzkEjC.bzcpg.cn
http://BKwReRd1.bzcpg.cn
http://2364t8Kg.bzcpg.cn
http://uKeG5hyp.bzcpg.cn
http://jXzGyPwC.bzcpg.cn
http://EskdbuqV.bzcpg.cn
http://c5JLG1ke.bzcpg.cn
http://o1cOo3zz.bzcpg.cn
http://r2LKkGZM.bzcpg.cn
http://rEJtKUai.bzcpg.cn
http://9u7rAZ7h.bzcpg.cn
http://sH0i0sLX.bzcpg.cn
http://Nq93EE3S.bzcpg.cn
http://Jz3sLTiR.bzcpg.cn
http://49VHzRlo.bzcpg.cn
http://1wFw3n44.bzcpg.cn
http://qmAOgmb2.bzcpg.cn
http://www.dtcms.com/a/383647.html

相关文章:

  • 【JavaSE五天速通|第三篇】常用API与日期类篇
  • JavaWeb-Session和ServletContext
  • HTML 编码规范
  • 深度学习(九):逻辑回归
  • 【LeetCode 每日一题】36. 有效的数独
  • 单表查询要点概述
  • 【Trans2025】计算机视觉|即插即用|WSC:即插即用!WSC模块,高光谱图像分类新SOTA!
  • Java面试小册(3)
  • 微服务项目测试接口一次成功一次失败解决办法
  • GPIO 之 EMIO 按键控制 LED 实验
  • centos安装 GNOME 桌面环境
  • 高并发投票功能设计
  • (B2B/工业/医疗行业)GEO优化服务商有哪些?哪家好?供应商推荐
  • unordered_map使用MFC的CString作为键值遇到C2056和C2064错误
  • MFC_Install_Create
  • 大数据知识框架思维导图(构造知识学习框架)
  • Spring Boot 集成第三方 API 时,常见的超时与重试机制设计
  • 设计模式——创建型模式
  • Nginx_Tomcat综合案例
  • Java常见类类型与区别详解:从实体类到异常类的全面指南
  • MOS管驱动栅极出现振铃现象
  • camke中采用vcpkg工具链设置OSG时
  • 玩转ElasticSearch
  • 设计模式-模板模式详解
  • GDB调试技巧实战--揪出内存泄漏元凶
  • LLM基础-工程化
  • Ubuntu系统下交叉编译Android的Lame库
  • AI 重构医疗:辅助诊断、药物研发、健康管理的三大落地场景实践
  • MySQL的日志系统(redolog、binlog、WAL技术)
  • 贪心算法应用:半导体晶圆生产问题详解