Explore Enterprise Education Gitee Premium Gitee AI AI teammates
Fetch the repository succeeded.
Create your Gitee Account
Explore and code with more than 14 million developers,Free private repositories !:)
Sign up
Already have an account? Sign in
文件
master
Branches (2)
master
neo
master
Branches (2)
master
neo
Clone or Download
Clone/Download
Prompt
To download the code, please copy the following command and execute it in the terminal
To ensure that your submitted code identity is correctly recognized by Gitee, please execute the following command.
When using the SSH protocol for the first time to clone or push code, follow the prompts below to complete the SSH configuration.
1 Generate RSA keys.
2 Obtain the content of the RSA public key and configure it in SSH Public Keys
To use SVN on Gitee, please visit the usage guide
When using the HTTPS protocol, the command line will prompt for account and password verification as follows. For security reasons, Gitee recommends configure and use personal access tokens instead of login passwords for cloning, pushing, and other operations.
Username for 'https://gitee.com': userName
Password for 'https://userName@gitee.com': # Private Token
master
Branches (2)
master
neo
index.html 18.87 KB
Copy Edit Raw Blame History
avalonjs authored 2015年11月29日 15:22 +08:00 . update
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
<h1 class="page-header">组件</h1>
<h2>介绍</h2>
<p>avalon1.5新增的特性, 旨在简化原ms-widget复杂的组件定义方式,使用更直观的自定义标签来创建组件.</p>
<p>avalon的组件是以UI库为单位设计,换言之,一个组件必须隶属于某一个UI库.默认,avalon已经创建好一个叫ms的UI库.
我们可以通过avalon.library方法来创建自己的组件库
</p>
<xmp class="javascript">
avalon.library("oni", {
$init: function(){},
$childReady: function(){},
$ready: function(){},
$dispose: function(){}
})
</xmp>
<ul>
<li>$init: Function 该组件开始渲染时调用的回调</li>
<li>$childReady: Function 该组件的子组件渲染完毕,冒泡上来的回调</li>
<li>$ready: Function 该组件渲杂完毕时调用的回调,它位于其所有子组件的$ready之后</li>
<li>$dispose: Fuction 该组件被移出DOM树,并且元素不存在msRetain属性,才会调用的回调</li>
</ul>
<p>我们通过avalon.component 来创建一个组件</p>
<xmp class="javascript">
avalon.component("ms:button", {
a: 1,
$replace: 1,
$ready: function () {
console.log("BUTTON构建完成")
},
$template: "<button type='button' >{{a}}<ms:text/></button>"
})
</xmp>
<p>配置对象有如下几个特殊的配置项:</p>
<ul>
<li>$replace: Boolean, 真值时表示替换其容器</li>
<li>$slot: String 默认插入点的名字</li>
<li>$template: String 组件的模板</li>
<li>$extend: String 指定要继承的组件名</li>
<li>$container: DOM 插入元素的位置,比如dialog就不一定在使用它的位置插入,通常放在body中</li>
<li>$construct: Function 用于调整三个配置项的合并,默认是function:(a, b,c ){return avalon.mix(a, b,c)}</li>
<li>$$template Function 用于微调组件的模板,传入$template与当前元素</li>
<li>$init: Function 刚开始渲染时调用的回调, 传入vm与当前元素</li>
<li>$childReady: Function 当其子组件$ready完毕后, 会冒泡到当前组件触发的回调, 传入vm与当前元素</li>
<li>$ready: Function 当组件的所有子组件都调用其$ready回调后才触发的回调, 传入vm与当前元素</li>
<li>$dispose: Function 该组件被移出DOM树,并且元素不存在msRetain属性时的销毁回调, 传入vm与当前元素</li>
</ul>
<p>当vm构建好时, $replace, $slot, $template,$container, $construct会消失</p>
<p>我们可以在</p>
<ul>
<li>$init中添加各种$watch回调, 为IE6-8的VBscript函数的this指向不正确进行bind fix</li>
<li>$ready中重新计算组件的高宽</li>
<li>$dispose中将VM中的元素节点置为null,移除各种dom事件,清空元素内部,方便GC</li>
</ul>
<p>此外,每个组件VM,还添加了一个叫 <strong>$refs</strong> 的非监控对象属性,用于存放子组件的VM。</p>
<h2 id="callbacks">所有回调的执行顺序</h2>
<xmp class="javascript">
组件自身的$$template -->
组件自身的$init --> 库的全局$init -->
组件自身的$childReady --> 库的全局$childReady -->
组件自身的$ready --> 库的全局$ready -->
组件自身的$dispose--> 库的全局$dispose
</xmp>
<h2 id="config">组件的配置</h2>
<xmp class="javascript">
avalon.component("ms:arcus", {
a: 1,
$template: "<button type='button'>{{a}}</button>"
})
</xmp>
<p>这里配置<ms:arcus>这种类型的基本属性与方法,目前,其中a一个属性</p>
<p>然后,我们在页面上调用它时,可以通过<strong>config</strong>属性指定它在VM中的业务数据</p>
<xmp class="html">
<ms:button config="buttonOpts"></ms:button>
</xmp>
<xmp class="javascript">
avalon.define({
$id: "test",
$skipArray:["butttonOpts"],
buttonOpts: {
a: 555
}
})
</xmp>
<p>如果你有多个ms:button组件,每个都有不同的配置对象,你可以使用ms-attr-config来动态生成config的值。</p>
<xmp class="html">
<div ms-repeat=array><ms:button ms-attr-config="opts{{$index}}"></div>
</xmp>
<p>如果你嫌这样麻烦,不想在VM上加这配置属性,还可以使用ms-data-button-a来生成这个值。</p>
<xmp class="html">
<div ms-repeat=array><ms:button ms-data-button-a="$index+ 10"></div>
</xmp>
<p>如果你连这个也不想,那么框架就会在已有的VM链上寻找<b>默认配置对象</b>。比如你的自定义签标的tagName为&lt;ms:dropdown&gt;,
那你在已有VM上定义一个叫ms:dropdown的对象就行了。如果你的自定义标签存在横线,比如ms:color-picker,那么它的默认配置对象
应为ms:colorPicker。
</p>
<p>因此通过,在avalon.component定义的共公配置对象,加上 VM上指定的个性化配置对象,
加上每个元素上使用ms-data指定的dataset配置对象,能让每个button实例都尽然不同!
</p>
<p>此外,我们还可以使用<strong>$id或identifier</strong>属性来指定组件VM的$id,不过当我们用ms-attr-$id动态生成$id可能有问题,
因为$是DOM属性中不是一个合法字符,我们只能用ms-attr-identifier来动态生成它。</p>
<xmp class="html">
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="avalon.js"></script>
</head>
<body>
<script>
var vm = avalon.define({
$id: "test",
array: [1, 2, 3],
$skipArray: ["x0", "x1", "x2"],
x0: {//x0, x1, x2为ms:button的配置对象
a: "aaa",
"ms:text": {//这个为ms:button的ms:text的默认配置对象
b: 44
}
},
x1: {
a: "222",
"ms:text": {
b: 55
}
},
x2: {
a: "333",
"ms:text": {
b: 66
}
}
})
avalon.component("ms:button", {
a: 1,
$replace: 1,
$ready: function (vm, elem) {
console.log("BUTTON构建完成")
},
$template: "<button type='button'><span>|<ms:text></ms:text>|</span>{{a}}<ms:text/></button>"
})
avalon.component("ms:text", {
b: "默认值",
$replace: 1,
$ready: function () {
console.log("TEXT构建完成")
},
$template: "<strong>{{b}}</strong>"
})
</script>
<div ms-controller="test">
<ms:button ms-repeat="array" ms-attr-config="x{{$index}}" ></ms:button>
</div>
</body>
</html>
</xmp>
<p><img src="../../assets/css/component/component01.png" /></p>
<xmp class="html">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
div {height:50px;width:200px;background:green;margin:5px;}
</style>
<script src="avalon.js"></script>
<script>
avalon.component('ms:abc', {
$template: '<div></div>',
onClick: function () {
},
$ready: function (vm, el) {
console.log(vm.$id)
}
});
var vm = avalon.define({
$id: 'test',
arr: [1, 2, 3]
})
</script>
</head>
<body ms-controller="test">
<header>
<ms:abc ms-repeat="arr" ms-attr-identifier="abc{{$index}}" ></ms:abc>
</header>
</body>
</html>
</xmp>
<p><img src="../../assets/css/component/component03.png" /></p>
<p>注意,$refs只保存其子组件的VM,不保存其子组件的子组件的VM!
并且$refs里面的内容是你自己在$childReady回调添加,框架不会帮你做的.</p>
<xmp class="html">
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="avalon.js"></script>
</head>
<body>
<script>
var vm = avalon.define({
$id: "test"
})
avalon.libraries.ms.$childReady = function (vm, e) {
var child = e.vm
vm.$refs[child.$id] = vm
}
avalon.component("ms:ancestor", {
a: 111,
$ready: function () {
console.log("ancestor构建完成")
},
$template: "<div><ms:parent></ms:parent>{{a}}<ms:parent></ms:parent></div>"
})
avalon.component("ms:parent", {
p: 222,
$ready: function () {
console.log("parent构建完成")
},
$template: "<div><ms:son></ms:son>{{p}}<ms:son></ms:son></div>"
})
avalon.component("ms:son", {
s: 333,
$ready: function () {
console.log("son构建完成")
},
$template: "<strong>{{s}}</strong>"
})
</script>
<div ms-controller="test">
<ms:ancestor $id="pope"/>
</div>
</body>
</html>
</xmp>
<p><img src="../../assets/css/component/component02.png" /></p>
<h2 id="slot">插入点的使用</h2>
<p>我们可以在代表组件的自定义标签的内部,添加一些带slot属性的标签,它们会自动赋给组件VM的同名属性中.</p>
<xmp class="html">
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="avalon.js"></script>
<script>
function heredoc(fn) {
return fn.toString()
.replace(/^[^\/]+\/\*!?\s?/, '')
.replace(/\*\/[^\/]+$/, '')
}
avalon.component("ms:dialog", {
header: "",
footer: "",
content: "",
onClick: function () {
console.log(this)
},
$template: heredoc(function (vm) {
/*
<div class="dialog">
{{header|html}}
{{content|html}}
{{footer|html}}
</div>
*/
})
})
avalon.define({
$id: "test",
a: "这是内容"
})
</script>
</head>
<body ms-controller="test">
<ms:dialog>
<div slot="header">弹出层的头部</div>
<div slot="content">
{{a}}
</div>
<div slot="footer">弹出层的底部</div>
</ms:dialog>
</body>
</html>
</xmp>
<p>这些带solt的元素叫做插入元素,它们在$init回调后进行收集, 收集完毕, 代表组件的自定义标签的innerHTML将会被其$template属性重写,
之后,这些插入元素会根据slot值进行分类,放到一个个文档碎片对象上.
然后这些文档碎片将插入到$template中的<strong ms-skip>{{xxx|html}}</strong>位置上.
</p>
<p><img src="../../assets/css/component/slot01.png" width="50%" height="50%"/></p>
<p><img src="../../assets/css/component/slot02.png" width="50%" height="50%" /></p>
<p><img src="../../assets/css/component/slot03.png" width="50%" height="50%"/></p>
<p>插入元素的定义有严格的要求,它必须是自定义元素的直接子节点. 如果这些节点中没有 slot 属性,并且你没有指定$slot的值 ,那么就没有插入点,
如果你指定了slot属性,并且也指定了$slot,那么除了那些指定了slot属性的节点,其他子节点都是$slot的
</p>
<p><b>avalon1.5.5</b>中,自定义标签支持由取其on-xxx属性,框架会将它转换为onXXX,属性值为一个函数名,框架会在之前的vmodels中查找,
最后将它合并到组件VM中.
</p>
<h2 id="getvm">获取组件VM</h2>
<xmp class="html">
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="avalon.js"></script>
<script type="text/javascript">
var tabVM
avalon.library("test", {
$ready: function (vm) {
if (vm.$id === "tab1") {
//在这里操作
tabVM = vm
console.log(vm.$id)
console.log(vm)
}
}
})
avalon.component("test:tab", {
$template: '<h1>{{content|html}}</h1>',
content: "", //插入点机制
$slot: "content", //插入点机制
$init: function (vm, el) {
},
$ready: function (vm, el) {
},
$dispose: function (vm, el) {
el.innerHTML = "";
}
});
</script>
<script type="text/javascript">
avalon.ready(function () {
var vm = avalon.define({
$id: "test",
onClick: function () {
if (tabVM) {
alert("onClick " + tabVM.$id)
}
}
});
avalon.scan(document.body, vm);
});
</script>
</head>
<body ms-controller="test">
<div ms-click="onClick">点我</div>
<test:tab $id="tab1" >这是tabs中的内容</test:tab>
</body>
</html>
</xmp>
<p>缺点是需要预先指定组件VM的$id</p>
<xmp class="html">
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="avalon.js"></script>
<script type="text/javascript">
var tabVM
avalon.component("test:tab", {
$template: '<h1>{{content|html}}</h1>',
content: "", //插入点机制
$slot: "content", //插入点机制
onInit: function () {
}, //必须定义此接口
$init: function (vm, el) {
},
$ready: function (vm, el) {
vm.onInit(vm)
},
$dispose: function (vm, el) {
el.innerHTML = "";
}
});
</script>
<script type="text/javascript">
avalon.ready(function () {
var vm = avalon.define({
$id: "test",
getVM: function (vm) {//用来重写onInit
tabVM = vm
//这里继续做其他事
},
onClick: function () {
if (tabVM) {
alert("onClick " + tabVM.$id)
}
}
});
avalon.scan(document.body, vm);
});
</script>
</head>
<body ms-controller="test">
<div ms-click="onClick">点我</div>
<test:tab on-init="getVM" >这是tabs中的内容</test:tab>
</body>
</html>
</xmp>
<p>此例则不需要指定VM,有点麻烦,但通用性更好</p>
<h2 id="construct">组件的构建全过程</h2>
<p>avalon的扫描器从上往下扫描, 如果遇到带<b>:</b>号的自定义标签,就默认为是组件,如果它上面存在一个叫msResolved属性,那么立即开始构建过程.</p>
<p>如果没有msResolved属性,就把此元素的相关信息放到一个叫componentQueue列队中.</p>
<p>待到该组件的JS文件加载下来,执行avalon.component方法时,componentQueue就会被重新检测,如果符合条件,就执行它的构建过程</p>
<p>构建过程以下:</p>
<fieldset>
<ol>
<li>设置一变量dependencies,其值为1</li>
<li>读取其所有属性,去掉其中的$id, config, id, class, tabindex, style,
ms-*属性,data-*属性,构成一个叫elemOpts的对象</li>
<li>读取其config属性, 从上层的VM中查找与其值同名的对象, 称之为vmOpts对象</li>
<li>将上面的对象与组件的定义对象,合并成一个对象, 这个合并过程可以通过$construct方法进行微调.
否则默认的$construct方法就相当于avalon.mix .</li>
<li>去掉合并对象中$replace, $slot, $template, $container,$construct属性, 然后放进avaon.define中转换一个VM, 称之为组件VM</li>
<li>将当前自定义元素的msResolved属性设置为1 </li>
<li>遍历其子节点,读取它们slot属性,然后 分类,并且一个个文档碎片对象,重赋对应的VM属性</li>
<li>将原$tempate属性放进行$$template方法中进行微调,然后用innerHTML改写自定义标签的内部 </li>
<li>如果用户设置了$replace属性,那么用该元素的第一个子元素代替它自身</li>
<li>如果用户设置了$container属性,那么将该元素移动到新容器之下</li>
<li>然后触发一个datasetchanged事件, 通知上层组件将dependencies减1</li>
<li>为自己绑定一个datasetchanged事件,用于接收下层组件发出来的datasetchanged事件.</li>
<li>开始扫描此元素及其下级 </li>
<li>如果此元素没有孩子,立即触发datasetchanged事件,为自己的dependencies减1,否则将
dependencies减1的逻辑放到一个renderCallbacks的列队中,此列队会在其子节点扫描后执行.
</li>
<li>
datasetchanged事件的逻辑为: 当该组件的子组件初始化时,它们就会为dependencies加1,
ready时就会减1, 并将子组件的VM储放到其$refs对象中, 并且触发一个叫$childReady的回调.
当dependencies为0时,触发自身的ready回调,并移除datasetchanged事件,将此元素放进销毁检测列队
</li>
<li>销毁检测列队是当元素被移出DOM树,并其msRetain属性没指定时,就进行销毁. 这个销毁的检测时机有两利,一是全局的定时轮询,
如果浏览器支持DOMNodeRemovedFromDocument事件,那么也为此元素添加此事件.
</li>
<li>销毁时,会调用$dispose回调,并从avalon.vmodels中将其ID删掉.</li>
</ol>
</fieldset>
<h2 id="ie68">IE6-8的特殊处理</h2>
<p>由于IE6-8下VM是一个VBScript对象 ,函数中的this并不是指向VM,而是window,需要我们在库的$init方法统一hack一下!</p>
<xmp class="javascript">
avalon. libraries.ms.$init = function(vm){
for(var i in vm){
if(vm.hasOwnProperty(i) && typeof vm[i] === "function"){
vm[i] = vm[i].bind(vm)
}
}
}
</xmp>
<p>如果你的组件是以ms为命名空间的话, 不需要使用avalon.librarys("ms"), 否则就要像下面这样做</p>
<xmp class="html">
<script src="avalon.js"></script>
<script>
avalon.library("oni") //这个东西必须跟挨着avalon库,并且放到head标签中
</script>
</xmp>
<p>如果你是使用requirejs加载avalon库, 那你需要在head标签中插入以下脚本</p>
<xmp class="html">
<script src="avalon.js"></script>
<script>
if (document.namespaces) {
document.namespaces.add("oni", 'http://www.w3.org/1999/xhtml')
}
</script>
</xmp>
<h2 id="tag">自定义标签是没有半闭合一说</h2>
<p>
&lt;xx:aaa /&gt;浏览器总是将它解析成&lt;xxx:aaa&gt;&lt;/xxx:aaa&gt;,
如果它后跟着一个元素,就悲剧了!&lt;xxx:aaa/&gt;&lt;strong&gt;111&lt;/strong&gt;,
本来设想好的平级关系变成父子关系了,
&lt;xxx:aaa&gt;&lt;strong&gt;111&lt;/strong&gt;&lt;/xxx:aaa&gt;
</p>
Loading...
Report
Report success
We will send you the feedback within 2 working days through the letter!
Please fill in the reason for the report carefully. Provide as detailed a description as possible.
Please select a report type
Cancel
Send
误判申诉

此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。

如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。

取消
提交

Releases

No release

Contributors

All

Activities

can not load any more
Edit
About
Homepage
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/web3d/avalonjs.github.io.git
git@gitee.com:web3d/avalonjs.github.io.git
web3d
avalonjs.github.io
avalonjs.github.io
master
Going to Help Center

Search

Comment
Repository Report
Back to the top
Login prompt
This operation requires login to the code cloud account. Please log in before operating.
Go to login
No account. Register

AltStyle によって変換されたページ (->オリジナル) /