字数:2543
阅读时间:15分钟
前言
上一篇文章我们讲述了JSDuck的详细用法。那么,本文笔者就以实例为基础,和大家一起,从零开始,搭建一个简单的API文档——我们的第一个API文档V0.0.1。
上一篇文章的入口处 ===> JSDuck用法详解
正文
首先,我们确定框架的基本内容:一个动物基类,然后派生出猫和狗两个子类。动物基类中有一个动物描述属性和吃饭方法,其派生类猫拥有奔跑、玩耍两个方法,外加一个发出声音的事件。
整体内容就这么多,非常简单哈,那下面我们就来看看该如何构建整个框架。
1.构建基础代码
磨刀不误砍柴工,首先,我们需要构建好基础代码。根据所需内容确定,我们需要构建一套完整的创建类和继承类的方案。那么,第一步,我们创建一个base.js文件来盛放基础代码。
var GM = {};
window.GM = GM;
/**
* 基础类的通用API类
* @class GM.Util
* @author lsjcoder
* @docauthor lsjcoder
* @static
*/
GM.Util = {
/**
* 扩展对象
* @method extend
* @static
* @param dest
* {Object} 任意对象
* @return {Object} 扩展后的对象
*/
extend : function(dest) { // (Object[, Object, ...]) ->
var sources = Array.prototype.slice.call(arguments, 1), i, j, len, src;
for (j = 0, len = sources.length; j < len; j++) {
src = sources[j] || {};
for (i in src) {
if (src.hasOwnProperty(i)) {
dest[i] = src[i];
}
}
}
return dest;
}
};
在创建好的文件内,我们先编写上述代码。我们先声明了类 GM.Util ,在类的注释上添加 @static
标签表示静态类。静态类中包含一个方法 extend ,实现了一个简单的扩展功能,后面类的继承需要用到这个接口。(这里需要注意,静态类中,所有的成员也都是静态的。因此,所有的成员必须加上@static
标签)。
/**
* 所有类的基类
* @class GM.Class
*/
GM.Class = function() {
/**
* @property {String} version 版本号
* @readonly
*/
this.version = "0.0.1";
};
声明顶层基类 GM.Class ,框架中所有的类都派生自该类。类中声明了一个 version 属性,该属性是字符串类型,并且是只读属性。
/**
* 基类的扩展方法
* @method extend
* @static
* @param {Object}
* props 包含需要扩展的成员的对象
* @return {Object} 扩展后的类
*/
GM.Class.extend = function(props) {
// extended class with the new prototype
var NewClass = function() {
// call the constructor
if (this.initialize) {
this.initialize.apply(this, arguments);
}
// call all constructor hooks
if (this._initHooks) {
this.callInitHooks();
}
};
// instantiate class without calling constructor
var F = function() {
};
F.prototype = this.prototype;
var proto = new F();
proto.constructor = NewClass;
NewClass.prototype = proto;
// inherit parent's statics
for ( var i in this) {
if (this.hasOwnProperty(i) && i !== 'prototype') {
NewClass[i] = this[i];
}
}
// mix static properties into the class
if (props.statics) {
GM.Util.extend(NewClass, props.statics);
delete props.statics;
}
// mix includes into the prototype
if (props.includes) {
GM.Util.extend.apply(null, [ proto ].concat(props.includes));
delete props.includes;
}
// merge options
if (props.options && proto.options) {
props.options = GM.Util.extend({}, proto.options, props.options);
}
// mix given properties into the prototype
GM.Util.extend(proto, props);
proto._initHooks = [];
var parent = this;
// jshint camelcase: false
NewClass.__super__ = parent.prototype;
// add method for calling all hooks
proto.callInitHooks = function() {
if (this._initHooksCalled) {
return;
}
if (parent.prototype.callInitHooks) {
parent.prototype.callInitHooks.call(this);
}
this._initHooksCalled = true;
for (var i = 0, len = proto._initHooks.length; i < len; i++) {
proto._initHooks[i].call(this);
}
};
return NewClass;
};
基类GM.Class中包含一个静态方法,用于实现类的继承机制。后续代码中类的封装和继承都是使用该方法完成的。
/**
* @enum GM.Enum.Sex 性别枚举
*/
GM.Enum.Sex = {
/**
* 男
*/
"0":"男",
/**
* 女
*/
"1":"女"
}
基础代码中,还声明了一个性别枚举,以供后续使用。
至此,基础代码构建完毕。
2.构建动物基类代码
在这个环节中,我们需要构建一个动物基类。首先,我们创建一个animal.js文件盛放代码。
文件完整代码如下:
/**
* 动物类
* @class GM.Animal
* @alias Animal
* @abstract
* @extends GM.Class
* @new
* @author lsjcoder
* @docauthor lsjcoder
*/
GM.Animal = GM.Class.extend({
/**
* @method constructor
* @cfg {Object} configs 传入参数
* @cfg {String} configs.name 姓名
* @cfg {Number} configs.age 年龄
* @cfg {"男"/"女"} configs.sex 性别
*/
initialize:function(configs){
this.props.name = configs.name;
this.props.age = configs.age;
this.props.sex = configs.sex;
},
/**
* @property {Object} props 属性
* @property {String} props.name 姓名
* @property {Number} props.age 年龄
* @property {GM.Enum.Sex} props.sex 性别
* @property {String} props.color 颜色
* @property {String} props.type 品种
*/
props:{
name:"",
age:0,
sex:"男",
color:"",
type:""
},
/**
* 吃饭
* @method eat
* @abstract
* @param {String} food 食物
* @return {Boolean} 是否进食
*/
eat:function(food){
if(food != null || food !== ""){
return true;
}
return false;
}
});
我们创建了一个动物类 GM.Animal ,该类不需要实现任何方法,所以,我们给他添加一个抽象标签 @abstract
表明该类是一个抽象类。@extends GM.Class
表明了该类派生自 GM.Class 类,@new
标签表示此类是这个版本新增加的内容。
类中有一个 initialize 方法,它是类的构造函数。所以我们用注释 @method constructor
标记它为构造函数,然后使用 @cfg
标签描述构造函数所需参数。这里,构造函数所需参数是一个对象,对象中有多个属性,所以我们使用如上配置方式来分别描述每一个属性。类中还有一个 props 属性,描述了动物的基本信息,该属性也是一个对象,注释方式同上述 @cfg
。最后,类中还有抽象方法 eat ,该方法接收一个字符串类型参数并返回一个布尔类型的结果。
3.构建子类猫和狗的代码
接下来,我们需要构建动物类的两个派生类:猫类和狗类。我们分别创建两个代码文件:cat.js、dog.js。
cat.js文件中代码如下:
/**
*猫
*
*```
*示例:
*var pCat = new GM.Cat({
* name:"Kity",
* age:1,
* sex:"女"
*})
*```
*
* @class GM.Cat
* @extends GM.Animal
* @alias Cat
* @author lsjcoder
* @docauthor lsjcoder
* @uses GM.Dog
*
*/
GM.Cat = GM.Animal.extend({
/**
* @method constructor
* @cfg {Object} configs 传入参数
* @cfg {String} configs.name 姓名
* @cfg {Number} configs.age 年龄
* @cfg {"男"/"女"} configs.sex 性别
*/
initialize:function(configs){
this.props.name = configs.name;
this.props.age = configs.age;
this.props.sex = configs.sex;
/**
* @event say 发出叫声
* @param {GM.Cat} this 当前实例
* @param {String} value 叫声
*/
this.fireEvent("say", this, value);
},
/**
* @method run 奔跑,已经废弃,请使用 {@link GM.Cat#startRun} 方法代替
* @removed
*/
run:function(){
this.bRun = true;
},
/**
* @method startRun 开始奔跑
* @return {Boolean} 开始奔跑是否成功
*/
startRun:function(){
if(this.bRun === true){
return false;
}
this.bRun = true;
return true;
},
/**
* @method playWithDog 与小狗一起玩耍
* @param {GM.Dog} pDog 小狗
*/
playWithDog:function(pDog){
this.player = pDog;
}
});
类 GM.Cat 派生自GM.Animal ,其中需要强调的有以下几点:
*```
*示例:
*var pCat = new GM.Cat({
* name:"Kity",
* age:1,
* sex:"女"
*})
*```
这段注释是描述了一个使用该类的示例,使用的是markdown语法来注释的。在文字的首尾分别添加符号 "`
" 就可以表明注释代码,但是注意该符号一定要换行使用,否则无法生效。
/**
* @event say 发出叫声
* @param {GM.Cat} this 当前实例
* @param {String} value 叫声
*/
this.fireEvent("say", this, value);
这段注释表明,类 GM.Cat 拥有一个名称为 “say” 的事件,该事件有两个参数,一个是当前实例,另外一个是字符串类型的叫声。
* @property {"男"/"女"} configs.sex 性别
* @property {GM.Enum.Sex} props.sex 性别
上面代码是描述枚举的两种方式。
dog.js代码和cat.js代码基本一致,这里就不再多做累述了。
至此,我们所有的代码构建工作就结束了,整个代码结构如下图所示
4.生成文档
接下来,就是最后一步了——使用工具生成文档。
我们在与代码同级的目录下,创建一个 jsduck.json 配置文件,以便工具使用。配置文件内容如下:
{
"--title": "我是一个示例文档",
"--welcome": "welcome.html",
"--warnings": ["-link", "-no_doc"],
"--seo": true,
"--": [
"./code"
],
"--output": "./docs",
"--examples-base-url": "../examples",
"--examples": "./examples.json",
"--body-html": [
""
],
"--categories":"./categories.json"
}
我们配置输入文件为整个代码文件夹,解析所有代码并生成文档。这里,我们配置了一个 examples.json 文件作为示例配置文件,文件内容如下:
[
{
"title": "样例展示",
"items": [
{
"name": "test-example",
"title": "cat类使用示例",
"description": "cat类使用示例",
"url": "/example.html",
"icon": "user.png",
"status": "updated"
}
]
}
]
这里,我们配置了 examples 目录下的 example.html 文件作为示例页面。
然后,里面还配置了一个 categories.json 文件作为代码分类配置,文件内容如下:
[
{
"name": "Common",
"groups": [
{
"name": "Base",
"classes": [
"GM.Class",
"GM.Util"
]
},
{
"name": "Animal",
"classes": [
"GM.Animal",
"GM.Cat",
"GM.Dog"
]
}
]
}
]
该配置将代码中的类分为了两组:Base 和 Animal 。这里需要注意,JSDuck中代码分类配置限制死了,只能配三级结构,不能做其他级别的配置。
好啦!至此,所有的准备工作就全部完成啦!
此时,我们只需要在 jsduck.json 目录下,轻轻地输入命令 jsduck
,就可以看到随着命令执行的结束,同级目录下生成了一个 docs文件夹。这个文件夹就是我们的文档成果,进入该文件夹,打开页面 template.html ,就可以看到我们今天的劳动成果啦!
晒一张成果图,与大家共勉:
关于JSDuck的学习和实践的分享,到这里就告一段落啦。希望对大家有所帮助,也随时欢迎大家和笔者讨论相关技术。
所有源码下载地址:https://pan.baidu.com/s/1dE88lPZ
欢迎关注我的微信公众号: