项目结构
以下是对上面 Dojo 单页应用(SPA)项目的总结,包括项目结构、路由管理、组件写法等关键点。
1. 项目结构
一个典型的 Dojo 单页应用项目结构如下:
/my-spa
  ├── index.html        // 主 HTML 文件
  ├── app.js            // 应用入口文件,处理路由和初始化
  ├── views/            // 视图组件目录
  │   ├── Home.js       // Home 组件
  │   ├── About.js      // About 组件
  │   └── Contact.js    // Contact 组件
  ├── templates/        // 模板文件目录(可选)
  │   ├── Home.html     // Home 组件的 HTML 模板
  │   ├── About.html    // About 组件的 HTML 模板
  │   └── Contact.html  // Contact 组件的 HTML 模板
2. 路由管理
使用 dojo/router 处理路由,定义不同 URL 路径对应的视图组件。
示例:app.js
require([
  "dojo/dom",
  "dojo/router",
  "dojo/dom-construct",
  "views/Home",
  "views/About",
  "views/Contact",
  "dojo/domReady!"
], function(dom, router, domConstruct, Home, About, Contact) {
  // 获取内容区域
  var contentNode = dom.byId("content");
  // 定义路由
  router.register("/home", function() {
    domConstruct.place(new Home().domNode, contentNode, "only");
  });
  router.register("/about", function() {
    domConstruct.place(new About().domNode, contentNode, "only");
  });
  router.register("/contact", function() {
    domConstruct.place(new Contact().domNode, contentNode, "only");
  });
  // 设置默认路由
  router.startup("/home");
});
3. 组件写法
每个视图组件通常继承自 dijit/_WidgetBase 和 dijit/_TemplatedMixin,并使用 templateString 定义模板。
示例:views/Home.js
define([
  "dojo/_base/declare",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dojo/text!./templates/Home.html" // 加载外部模板
], function(declare, _WidgetBase, _TemplatedMixin, template) {
  return declare([_WidgetBase, _TemplatedMixin], {
    // 使用外部模板
    templateString: template,
    // 组件属性
    userName: "Guest", // 默认值
    // 初始化逻辑
    postCreate: function() {
      this.inherited(arguments); // 调用父类的 postCreate 方法
      console.log("Home component initialized!");
    }
  });
});
示例:templates/Home.html
<div class="home-view">
  <h1>Welcome, ${userName}!</h1>
  <p>This is the Home view.</p>
</div>
4. 主 HTML 文件
在 index.html 中引入 Dojo 库和应用入口文件,并定义页面结构。
示例:index.html
<!DOCTYPE html>
<html>
<head>
  <title>Dojo SPA Example</title>
  <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dijit/themes/claro/claro.css">
  <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
  <script src="app.js"></script>
</head>
<body class="claro">
  <div id="appContainer">
    <!-- 导航栏 -->
    <div id="nav">
      <a href="#home">Home</a> |
      <a href="#about">About</a> |
      <a href="#contact">Contact</a>
    </div>
    <!-- 内容区域 -->
    <div id="content"></div>
  </div>
</body>
</html>
5. 关键点总结
- 
项目结构:
- 视图组件放在 
views/目录。 - 模板文件放在 
templates/目录(可选)。 app.js是应用入口文件,负责路由和初始化。
 - 视图组件放在 
 - 
路由管理:
- 使用 
dojo/router定义路由。 - 每个路由对应一个视图组件,通过 
domConstruct.place动态加载。 
 - 使用 
 - 
组件写法:
- 继承 
dijit/_WidgetBase和dijit/_TemplatedMixin。 - 使用 
templateString定义模板(可以直接写字符串或加载外部 HTML 文件)。 - 通过 
${variableName}注入变量。 
 - 继承 
 - 
主 HTML 文件:
- 引入 Dojo 库和应用入口文件。
 - 定义页面结构和导航栏。
 
 
6. 扩展功能
- 嵌套路由:支持更复杂的路由(如 
/user/:id)。 - 数据绑定:结合 
dojo/Stateful或dojo/store实现数据绑定。 - 动画效果:在切换视图时添加动画效果。
 - 国际化:使用 
dojo/i18n实现多语言支持。 
全局配置
在 Dojo 中,全局配置是通过 dojoConfig 对象来实现的。dojoConfig 允许你设置 Dojo 的各种选项和默认行为,这些配置会在 Dojo 加载时生效,并影响整个应用程序的运行方式。以下是关于 dojoConfig 的详细说明和使用方法:
1. dojoConfig 的基本用法
dojoConfig 必须在加载 dojo.js 之前定义,否则配置将不会生效。以下是一个简单的示例:
<script>
  dojoConfig = {
    has: {
      "dojo-firebug": true // 启用 Firebug Lite 调试功能
    },
    parseOnLoad: false, // 是否在页面加载时自动解析 Dojo 组件
    async: true, // 是否异步加载模块
    foo: "bar" // 自定义配置项
  };
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.3/dojo/dojo.js"></script>
2. 常用配置项
以下是 dojoConfig 中一些常用的配置项:
- 
has: 用于启用或禁用某些功能。例如:has: { "dojo-firebug": true, // 启用 Firebug Lite "dojo-debug-messages": true // 启用调试消息 } - 
parseOnLoad: 是否在页面加载时自动解析 Dojo 组件。默认值为false。 - 
async: 是否异步加载模块。默认值为true。 - 
baseUrl: 指定模块的根路径。例如:baseUrl: "/js/" - 
packages: 定义模块包的路径。例如:packages: [ { name: "myApp", location: "/js/myApp" } ] - 
deps: 指定在 Dojo 加载时需要立即加载的模块。例如:deps: ["dojo/domReady!"] - 
callback: 在deps加载完成后执行的回调函数。 
3. dojoConfig 与 dojo/_base/config 的区别
dojoConfig: 用于在 Dojo 加载时传递配置参数。dojo/_base/config: 在 Dojo 加载后,dojoConfig的配置会被复制到dojo/_base/config中,供模块代码使用。
4. 示例:动态加载配置
你可以通过 dojoConfig 动态加载配置,例如从查询字符串中获取配置:
<script>
  dojoConfig = {
    app: {
      userName: "Guest"
    }
  };
  // 从查询字符串中混入配置
  var queryParams = dojo.queryToObject(location.search.substring(1));
  dojo.mixin(dojoConfig.app, queryParams);
</script>
5. 注意事项
- 顺序:
dojoConfig必须在加载dojo.js之前定义。 - 兼容性:在 Dojo 1.6 之前,全局配置对象名为 
djConfig,但建议使用dojoConfig。 
6. 参考文档
更多关于 dojoConfig 的详细配置和使用方法,可以参考以下资源:
生命周期相关
在 Dojo 中,组件生命周期是指组件从创建到销毁的整个过程。Dojo 提供了一系列生命周期方法,允许你在组件的不同阶段执行自定义逻辑。以下是 Dojo 组件的主要生命周期方法及其使用方式:
1. 主要生命周期方法
| 方法名 | 描述 | 
|---|---|
constructor | 
组件构造函数,在组件实例化时调用。 | 
postscript | 
在组件初始化后调用,通常用于处理依赖注入。 | 
postCreate | 
在组件 DOM 结构创建后调用,通常用于初始化逻辑。 | 
startup | 
在组件及其子组件完全渲染后调用,通常用于布局和尺寸相关的逻辑。 | 
destroy | 
在组件销毁时调用,通常用于清理资源。 | 
2. 使用生命周期方法
示例:components/MyWidget.js
define([
  "dojo/_base/declare",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dojo/text!./templates/MyWidget.html"
], function(declare, _WidgetBase, _TemplatedMixin, template) {
  return declare([_WidgetBase, _TemplatedMixin], {
    templateString: template,
    // 构造函数
    constructor: function() {
      console.log("Constructor called");
    },
    // postscript 方法
    postscript: function() {
      console.log("Postscript called");
    },
    // postCreate 方法
    postCreate: function() {
      console.log("PostCreate called");
      this.inherited(arguments); // 调用父类的 postCreate 方法
    },
    // startup 方法
    startup: function() {
      console.log("Startup called");
      this.inherited(arguments); // 调用父类的 startup 方法
    },
    // destroy 方法
    destroy: function() {
      console.log("Destroy called");
      this.inherited(arguments); // 调用父类的 destroy 方法
    }
  });
});
示例:components/templates/MyWidget.html
<div class="my-widget">
  <p>This is MyWidget!</p>
</div>
3. 在页面中使用组件
示例:views/Home.js
define([
  "dojo/_base/declare",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dojo/text!./templates/Home.html",
  "components/MyWidget"
], function(declare, _WidgetBase, _TemplatedMixin, template, MyWidget) {
  return declare([_WidgetBase, _TemplatedMixin], {
    templateString: template,
    // 初始化逻辑
    postCreate: function() {
      this.inherited(arguments);
      // 实例化 MyWidget 组件
      var myWidget = new MyWidget({});
      this.domNode.appendChild(myWidget.domNode);
      // 手动调用 startup 方法
      myWidget.startup();
    }
  });
});
示例:views/templates/Home.html
<div class="home-view">
  <h1>Home Page</h1>
  <div data-dojo-attach-point="widgetPlaceholder"></div>
</div>
4. 生命周期方法调用顺序
当组件被实例化并插入到 DOM 中时,生命周期方法的调用顺序如下:
constructorpostscriptpostCreatestartup(需要手动调用)destroy(在组件销毁时调用)
5. 监听组件销毁
可以通过 on 方法监听组件的 destroy 事件。
示例:监听销毁事件
myWidget.on("destroy", function() {
  console.log("MyWidget destroyed");
});
6. 关键点总结
- 生命周期方法:
constructor、postscript、postCreate、startup和destroy是 Dojo 组件的主要生命周期方法。 - 手动调用 
startup:在组件完全渲染后,需要手动调用startup方法。 - 销毁清理:在 
destroy方法中清理资源,避免内存泄漏。 
7. 扩展功能
- 异步初始化:在 
startup方法中执行异步逻辑(如加载数据)。 - 事件监听:在 
postCreate方法中绑定事件监听器。 - 动态属性:在 
constructor或postCreate方法中初始化动态属性。 
dojo/csi 动态加载模板模块工具
dojo/csi 是 Dojo 提供的一个模块,用于在客户端动态加载和插入 HTML 片段。它的主要用途是将外部 HTML 文件的内容插入到当前页面的指定 DOM 元素中,类似于服务器端的 SSI(Server-Side Includes),但完全在浏览器中完成。
以下是 dojo/csi 的详细使用方法和示例。
1. 引入 dojo/csi
首先,在 HTML 文件中引入 Dojo 库和 dojo/csi 模块。
<!DOCTYPE html>
<html>
<head>
  <title>Dojo CSI Example</title>
  <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
</head>
<body class="claro">
  <div id="header"></div>
  <div id="content">
    <h1>Main Content</h1>
  </div>
  <div id="footer"></div>
  <script>
    require(["dojo/csi"], function(csi) {
      // 动态加载 HTML 片段
      csi("header", "templates/header.html");
      csi("footer", "templates/footer.html");
    });
  </script>
</body>
</html>
2. 创建 HTML 片段
在 templates/ 目录下创建需要加载的 HTML 片段。
示例:templates/header.html
<header>
  <h1>Welcome to My Website</h1>
  <nav>
    <a href="#home">Home</a> |
    <a href="#about">About</a> |
    <a href="#contact">Contact</a>
  </nav>
</header>
示例:templates/footer.html
<footer>
  <p>© 2023 My Website. All rights reserved.</p>
</footer>
3. 使用 dojo/csi 加载 HTML 片段
在 JavaScript 中调用 csi 函数,将 HTML 片段加载并插入到指定的 DOM 元素中。
示例:app.js
require(["dojo/csi"], function(csi) {
  // 动态加载 HTML 片段
  csi("header", "templates/header.html");
  csi("footer", "templates/footer.html");
});
4. 运行效果
- 页面加载时,
dojo/csi会动态加载header.html和footer.html。 - 加载的 HTML 片段会被插入到 
#header和#footer元素中。 - 最终页面结构如下:
<div id="header"> <header> <h1>Welcome to My Website</h1> <nav> <a href="#home">Home</a> | <a href="#about">About</a> | <a href="#contact">Contact</a> </nav> </header> </div> <div id="content"> <h1>Main Content</h1> </div> <div id="footer"> <footer> <p>© 2023 My Website. All rights reserved.</p> </footer> </div> 
5. dojo/csi 的详细用法
语法
csi(targetId, url, callback);
targetId:目标 DOM 元素的 ID,HTML 片段将被插入到这个元素中。url:要加载的 HTML 片段的 URL。callback(可选):HTML 片段加载完成后执行的回调函数。
示例:使用回调函数
require(["dojo/csi"], function(csi) {
  csi("header", "templates/header.html", function() {
    console.log("Header loaded!");
  });
});
6. 关键点总结
- 动态加载:
dojo/csi是异步加载的,不会阻塞页面渲染。 - HTML 片段:将公共的 HTML 片段放在外部文件中,便于复用和维护。
 - 插入目标:通过 
targetId指定 HTML 片段插入的位置。 
7. 扩展功能
- 加载失败处理:可以通过 
dojo/request模块处理加载失败的情况。 - 结合 Dojo 组件:可以将加载的 HTML 片段与 Dojo 组件结合,实现更复杂的功能。
 - 多片段加载:可以同时加载多个 HTML 片段,并分别插入到不同的 DOM 元素中。
 
xml 动态渲染组件思路
在 Dojo 中,XML 并不是直接用于定义组件或模板的格式,因为 Dojo 的组件系统是基于 JavaScript 和 HTML 的。然而,你可以通过以下方式将 XML 数据与 Dojo 结合使用:
1. 使用 XML 作为数据源
XML 可以作为数据源,动态生成 Dojo 组件或页面内容。Dojo 提供了 dojo/request 模块来加载 XML 数据,并通过 dojo/parser 或 dojo/dom-construct 动态生成组件。
示例:加载 XML 数据并生成组件
XML 数据:data/components.xml
<components>
  <component type="Header" title="Welcome to the Home Page" />
  <component type="Footer" />
</components>
加载 XML 并生成组件:app.js
require([
  "dojo/request",
  "dojo/dom-construct",
  "dojo/parser",
  "components/Header",
  "components/Footer"
], function(request, domConstruct, parser, Header, Footer) {
  // 加载 XML 数据
  request("data/components.xml", {
    handleAs: "xml"
  }).then(function(xml) {
    var components = xml.getElementsByTagName("component");
    for (var i = 0; i < components.length; i++) {
      var type = components[i].getAttribute("type");
      var props = {};
      for (var j = 0; j < components[i].attributes.length; j++) {
        var attr = components[i].attributes[j];
        props[attr.name] = attr.value;
      }
      // 动态创建组件
      var component;
      if (type === "Header") {
        component = new Header(props);
      } else if (type === "Footer") {
        component = new Footer(props);
      }
      // 插入组件到 DOM
      domConstruct.place(component.domNode, "content", "last");
    }
  });
});
2. 使用 XML 定义模板
虽然 Dojo 不支持直接使用 XML 定义模板,但可以通过工具(如 Gulp)将 XML 转换为 Dojo 组件代码。
示例:使用 Gulp 将 XML 转换为 Dojo 组件代码
XML 文件:src/xml/Home.xml
<components>
  <component type="Header" title="Welcome to the Home Page" />
  <component type="Footer" />
</components>
Gulp 任务:gulpfile.js
const gulp = require("gulp");
const xml2js = require("gulp-xml2js");
const replace = require("gulp-replace");
gulp.task("xml-to-dojo", function () {
  return gulp
    .src("src/xml/*.xml")
    .pipe(xml2js())
    .pipe(
      replace(/(<[^>]+>)/g, function (match, p1) {
        const tag = p1.replace(/<|>/g, "");
        const [type, ...props] = tag.split(" ");
        const propsStr = props
          .map((prop) => {
            const [key, value] = prop.split("=");
            return `${key}:${value}`;
          })
          .join(",");
        return `new ${type}({${propsStr}})`;
      })
    )
    .pipe(gulp.dest("src/components"));
});
gulp.task("default", gulp.series("xml-to-dojo"));
运行 gulp 后,XML 文件会被转换为 Dojo 组件代码,并输出到 src/components/ 目录。
3. 在 Dojo 项目中使用 XML
在 Dojo 项目中,可以直接使用生成的组件。
示例:src/views/Home.js
define([
  "dojo/_base/declare",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dojo/text!./templates/Home.html",
  "components/Header",
  "components/Footer"
], function(declare, _WidgetBase, _TemplatedMixin, template, Header, Footer) {
  return declare([_WidgetBase, _TemplatedMixin], {
    templateString: template,
    // 初始化逻辑
    postCreate: function() {
      this.inherited(arguments);
      // 使用生成的组件
      var header = new Header({ title: "Welcome to the Home Page" });
      var footer = new Footer({});
      this.domNode.appendChild(header.domNode);
      this.domNode.appendChild(footer.domNode);
    }
  });
});
4. 关键点总结
- XML 作为数据源:通过 
dojo/request加载 XML 数据,并动态生成组件。 - XML 转换为组件代码:使用 Gulp 将 XML 文件转换为 Dojo 组件代码。
 - 在 Dojo 项目中使用 XML:直接使用生成的组件。
 
5. 扩展功能
- 动态属性:可以在 XML 文件中定义动态属性,通过 Gulp 任务生成相应的代码。
 - 嵌套组件:支持在 XML 文件中定义嵌套组件结构。
 - 模板生成:可以将 XML 文件转换为 Dojo 模板文件(如 
.html)。 
xml中配置页面组件实现方式
你提到的项目通过XML文件配置Dojo组件,然后页面自动生成出来,这通常是通过以下技术实现的:
1. Dojo的声明式编程
Dojo支持声明式编程,即通过在HTML或XML文件中使用特定的标签或属性来定义组件,而不是通过JavaScript代码手动创建组件。这种方式可以让开发者更直观地配置UI组件。
实现步骤:
- 引入Dojo库:在页面中引入Dojo的JavaScript和CSS文件。
 - 使用
data-dojo-*属性:在HTML或XML文件中,使用data-dojo-type、data-dojo-props等属性来声明Dojo组件。 - 自动解析:Dojo的解析器(
dojo/parser)会自动扫描页面中的data-dojo-*属性,并根据这些属性创建对应的Dojo组件。 
示例:
<!-- 引入Dojo库 -->
<script src="path/to/dojo/dojo.js"></script>
<link rel="stylesheet" href="path/to/dojo/resources/dojo.css">
<!-- 声明式定义Dojo组件 -->
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Click Me'"></div>
<!-- 初始化解析器 -->
<script>
  require(["dojo/parser", "dijit/form/Button"], function(parser) {
    parser.parse(); // 解析页面中的Dojo组件
  });
</script>
在这个例子中:
data-dojo-type指定了组件的类型(如dijit/form/Button)。data-dojo-props用于设置组件的属性(如label: 'Click Me')。parser.parse()会扫描页面中的所有data-dojo-*属性,并自动创建对应的Dojo组件。
2. XML文件配置
在你的项目中,XML文件可能被用来定义Dojo组件的结构和属性。这些XML文件会被解析并转换为HTML,然后通过Dojo的声明式编程机制生成页面。
实现步骤:
- 定义XML文件:在XML文件中使用类似HTML的标签和属性来描述Dojo组件。
 - 解析XML文件:使用服务器端技术(如Java、PHP等)或前端技术(如JavaScript)将XML文件解析为HTML。
 - 注入到页面:将解析后的HTML注入到页面中,然后调用
parser.parse()生成Dojo组件。 
示例:
假设有一个XML文件config.xml:
<components>
  <button label="Click Me" type="dijit/form/Button" />
  <tree id="myTree" type="dijit/Tree" />
</components>
通过服务器端或前端解析,将其转换为HTML:
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Click Me'"></div>
<div id="myTree" data-dojo-type="dijit/Tree"></div>
然后在页面中调用parser.parse()生成组件。
3. 动态生成页面
如果项目需要根据XML文件动态生成页面,通常会结合以下技术:
- 服务器端渲染:使用Java、PHP、Python等服务器端语言解析XML文件,生成HTML并返回给客户端。
 - 前端渲染:使用JavaScript(如
DOMParser)解析XML文件,动态生成HTML并注入到页面中。 
示例(前端渲染):
// 假设从服务器获取XML文件
fetch('config.xml')
  .then(response => response.text())
  .then(xmlString => {
    // 解析XML
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xmlString, "text/xml");
    // 将XML转换为HTML
    const components = xmlDoc.getElementsByTagName('components')[0];
    let html = '';
    Array.from(components.children).forEach(component => {
      const type = component.getAttribute('type');
      const props = Array.from(component.attributes)
        .filter(attr => attr.name !== 'type')
        .map(attr => `${attr.name}: '${attr.value}'`)
        .join(', ');
      html += `<div data-dojo-type="${type}" data-dojo-props="${props}"></div>`;
    });
    // 注入到页面
    document.getElementById('container').innerHTML = html;
    // 解析Dojo组件
    require(["dojo/parser"], function(parser) {
      parser.parse();
    });
  });
4. 工具或框架支持
有些项目可能使用了特定的工具或框架来简化XML到页面的转换过程,例如:
- Dojo Build:通过Dojo的构建工具,将XML文件预编译为HTML或JavaScript。
 - 自定义模板引擎:使用模板引擎(如Handlebars、Mustache)将XML文件渲染为HTML。
 - 前端框架:结合Vue.js、React等框架,将XML文件作为数据源,动态生成组件。
 
总结
你的项目通过XML文件配置Dojo组件,并自动生成页面,可能是以下技术的结合:
- Dojo的声明式编程:使用
data-dojo-*属性定义组件。 - XML解析:将XML文件解析为HTML。
 - 动态注入:将解析后的HTML注入到页面,并调用
parser.parse()生成组件。 

                
            
        
浙公网安备 33010602011771号