├── .gitignore ├── CHANGELOG.md ├── IDE plugins ├── eclipse │ ├── HOWTO.md │ └── plugin_impexjs.zip └── sublime3 │ ├── HOWTO.md │ └── impex │ ├── Main.sublime-menu │ ├── README.md │ ├── impex.py │ ├── impex.sublime-settings │ ├── impex_global.sublime-completions │ ├── impex_lifecycle.sublime-completions │ └── impex_scope.sublime-completions ├── LICENSE ├── README.md ├── benchmark └── regparser.html ├── build ├── impex.dev.all.js ├── impex.dev.all.min.js ├── impex.prod.all.js └── impex.prod.all.min.js ├── examples ├── codes │ ├── VDOM update with events.html │ ├── VDOM update.html │ ├── calculator.html │ ├── component - anonymous.html │ ├── component - attributes.html │ ├── component - compare.html │ ├── component - computedstate.html │ ├── component - create.html │ ├── component - cross level var.html │ ├── component - event - keyboard.html │ ├── component - event.html │ ├── component - extends.html │ ├── component - is.html │ ├── component - lifecycle.html │ ├── component - mixins.html │ ├── component - named.html │ ├── component - nexttick.html │ ├── component - parent-children.html │ ├── component - props.html │ ├── component - this.html │ ├── component - watch.html │ ├── debug - stack.html │ ├── delimiters.html │ ├── directive - bind.html │ ├── directive - class.html │ ├── directive - cloak.html │ ├── directive - elseif.html │ ├── directive - event - bubbles.html │ ├── directive - event - keyboard.html │ ├── directive - event - mouseenter.html │ ├── directive - event.html │ ├── directive - for - component.html │ ├── directive - for - template.html │ ├── directive - for - template2.html │ ├── directive - for - to.html │ ├── directive - form.html │ ├── directive - html - for.html │ ├── directive - html.html │ ├── directive - if - template.html │ ├── directive - if test.html │ ├── directive - if.html │ ├── directive - model - attributes.html │ ├── directive - pre.html │ ├── directive - show on component.html │ ├── directive - show.html │ ├── directive - style.html │ ├── filter - chain.html │ ├── filter - currency.html │ ├── filter - for.html │ ├── global component ref.html │ ├── global event.html │ ├── global var.html │ ├── html-scope.html │ ├── nested.html │ ├── number.html │ ├── observe-array.html │ ├── observe-object.html │ ├── performence-nested.html │ ├── performence-parser.html │ ├── plugin - event.html │ ├── plugin - store.html │ ├── propsChange.html │ ├── ref.html │ ├── select.html │ ├── slot component.html │ ├── slot.html │ ├── store.html │ ├── test case - node update.html │ ├── todos.html │ ├── updateprop.html │ └── wishlist │ │ ├── css │ │ └── main.css │ │ ├── data.js │ │ ├── index.html │ │ └── js │ │ ├── components.js │ │ └── filters.js ├── index.html ├── lib │ ├── fontawesome │ │ ├── css │ │ │ ├── font-awesome.css │ │ │ └── font-awesome.min.css │ │ └── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ ├── impex │ │ ├── impex.dev.all.js │ │ ├── impex.ext.loadable.js │ │ ├── impex.ext.router.js │ │ ├── impex.ext.store.js │ │ └── impex.prod.all.js │ └── jq │ │ ├── jquery-3.1.0.min.js │ │ └── jquery.slimscroll.min.js └── themes │ ├── default.css │ ├── default.css.map │ └── default.scss ├── ext ├── impex.ext.loadable.js └── impex.ext.router.js ├── gulpfile.js ├── package.json └── src ├── component ├── Component.js ├── EventEmitter.js ├── Task.js └── watchers.js ├── core ├── Util.js ├── basic.js ├── compiler.js └── parser.js ├── directive └── build-in.js ├── filter └── build-in.js ├── impex.js ├── observe ├── Change.js ├── Monitor.js └── observer.js ├── shellEnd.js ├── shellStart.js └── vdom ├── builder.js ├── comparer.js ├── transform.js └── vnode.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /IDE plugins/eclipse/HOWTO.md: -------------------------------------------------------------------------------- 1 | # How to use? 2 | 3 | this zip file is a eclipse 3.x plugin, perform the following steps to manually install it. 4 | 5 | # Installation 6 | 7 | 1. Click the Help > Install New Software... menu 8 | 9 | 2. Chose the zip file to install 10 | 11 | -------------------------------------------------------------------------------- /IDE plugins/eclipse/plugin_impexjs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/IDE plugins/eclipse/plugin_impexjs.zip -------------------------------------------------------------------------------- /IDE plugins/sublime3/HOWTO.md: -------------------------------------------------------------------------------- 1 | # How to use? 2 | 3 | this 'impex' folder is a ST3 package, perform the following steps to manually install it. 4 | 5 | # Installation 6 | 7 | 1. Click the Preferences > Browse Packages… menu 8 | 9 | 2. Copy 'impex' folder into the Packages/ directory 10 | 11 | 3. Restart Sublime Text 12 | 13 | -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "file", 4 | "children": 5 | [ 6 | { 7 | "caption": "-" 8 | }, 9 | { 10 | "caption": "New Impex template file", 11 | "command": "new_impex_template" 12 | }, 13 | { 14 | "caption": "-" 15 | } 16 | ] 17 | }, 18 | { 19 | 20 | "id": "preferences", 21 | "children": 22 | [ 23 | { 24 | "id": "package-settings", 25 | "children": 26 | [ 27 | { 28 | "caption": "Impex", 29 | "children": 30 | [ 31 | { 32 | "caption": "README", 33 | "command": "open_file", "args": 34 | { 35 | "file": "${packages}/impex/README.md" 36 | } 37 | }, 38 | { 39 | "caption": "-" 40 | }, 41 | { 42 | "caption": "Settings – Default", 43 | "command": "open_file", "args": 44 | { 45 | "file": "${packages}/impex/impex.sublime-settings" 46 | } 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ] 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/README.md: -------------------------------------------------------------------------------- 1 | # impexST 2 | 3 | 提供impex API和内置指令的语法提示,以及快速模板创建菜单等 4 | 5 | # API 6 | ## impex 7 | * g 8 | * version 9 | * config() 10 | * component() 11 | * directive() 12 | * filter() 13 | * render() 14 | 15 | ## impex.Component 16 | * el 17 | * state 18 | * refs 19 | * name 20 | * parent 21 | * children 22 | * setState() 23 | * watch() 24 | 25 | ## VNode 26 | * on() 27 | * setAttribute() 28 | * getAttribute() 29 | 30 | ## Derective data 31 | * comp 32 | * value 33 | * args 34 | * exp 35 | 36 | 37 | # Derective 38 | * x-if 39 | * x-for 40 | * x-html 41 | * x-class 42 | * x-style 43 | * x-bind 44 | * x-on 45 | * x-show 46 | * x-model 47 | 48 | # Menu 49 | File -> New Impex template file 50 | -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/impex.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | mpx_all_directives = [ 5 | ["x-if","x-if=\"${1:exp}\""], 6 | ["x-for","x-for=\"${1:ds} as ${2:item}\""], 7 | ["x-for\tto","x-for=\"${1:begin} to ${2:end} as ${3:i}\""], 8 | ["x-html","x-html=\"${1:exp}\""], 9 | ["x-class","x-class=\"${1:exp}\""], 10 | ["x-style","x-style=\"${1:exp}\""], 11 | ["x-bind\tshortcut",".$1=\"${2:exp}\""], 12 | ["x-on\tshortcut",":$1=\"${2:exp}\""], 13 | ["x-show","x-show=\"${1:exp}\""], 14 | ["x-model","x-model=\"${1:exp}\""], 15 | ] 16 | 17 | mpx_custom_directives = [ 18 | ["x-if","x-if=\"${1:exp}\""], 19 | ["x-for","x-for=\"${1:ds} as ${2:item}\""] 20 | ] 21 | 22 | class ImpexAutocomplete(sublime_plugin.EventListener): 23 | def on_query_completions(self, view, prefix, locations): 24 | global mpx_all_directives, mpx_custom_directives 25 | if view.match_selector(locations[0], 'text.html.basic meta.tag.block.any.html punctuation.definition.tag.end.html'): 26 | return mpx_all_directives 27 | if view.match_selector(locations[0], 'text.html.basic meta.tag.custom.html'): 28 | return mpx_custom_directives 29 | return [] 30 | 31 | 32 | class NewImpexTemplateCommand(sublime_plugin.TextCommand): 33 | def run(self, edit): 34 | window = sublime.active_window() 35 | newView = window.new_file() 36 | # syntax = self.view.settings().get('syntax') 37 | # print(syntax) 38 | newView.set_syntax_file("Packages/HTML/HTML.sublime-syntax") 39 | newView.insert(edit, 0, 40 | "\n\n\n\n") -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/impex.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "use_current_file_syntax": true, 3 | 4 | "auto_complete_triggers": [ {"selector": "source.html,source.js", "characters": "."} ], 5 | } 6 | -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/impex_global.sublime-completions: -------------------------------------------------------------------------------- 1 | { 2 | "scope": "text.html.basic source.js.embedded.html, source.js", 3 | 4 | "completions": 5 | [ 6 | //global attr 7 | "impex", 8 | { "trigger":"g\timpex", "contents":"g"}, 9 | { "trigger":"version\timpex", "contents":"version"}, 10 | { "trigger":"config(\timpex", "contents":"config(${1:cfg})"}, 11 | { "trigger":"component(\timpex", "contents":"component(\"x-${1:name}\",{${2:...}})"}, 12 | { "trigger":"directive(\timpex", "contents":"directive(\"${1:name}\",{\n\tonBind:function(vnode,data){\n\t\t${2://todo...}\n\t}\n})"}, 13 | { "trigger":"filter(\timpex", "contents":"filter(\"${1:name}\",function(v,arg){\n\t${2://todo...}\n})"}, 14 | { "trigger":"render(\timpex", "contents":"render(${1:node},{${2:...}})"}, 15 | 16 | 17 | ] 18 | } -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/impex_lifecycle.sublime-completions: -------------------------------------------------------------------------------- 1 | { 2 | "scope": "text.html.basic source.js.embedded.html meta.block.js,text.html.basic source.js.embedded.html meta.function-call.method.js,source.js meta.block.js", 3 | 4 | "completions": 5 | [ 6 | //component 7 | { "trigger":"onCreate\tlifecycle com", "contents":"onCreate:function(){\n\t${1://todo...}\n}"}, 8 | { "trigger":"onBeforeCompile\tlifecycle com", "contents":"onBeforeCompile:function(tmpl){\n\t${1://todo...}\n}"}, 9 | { "trigger":"onCompile\tlifecycle com", "contents":"onCompile:function(vnode){\n\t${1://todo...}\n}"}, 10 | { "trigger":"onBeforeMount\tlifecycle com", "contents":"onBeforeMount:function(dom){\n\t${1://todo...}\n}"}, 11 | { "trigger":"onMount\tlifecycle com", "contents":"onMount:function(dom){\n\t${1://todo...}\n}"}, 12 | { "trigger":"onPropBind\tlifecycle com", "contents":"onPropBind:function(props){\n\t${1://todo...}\n}"}, 13 | { "trigger":"onPropChange\tlifecycle com", "contents":"onPropChange:function(newProps,oldProps){\n\t${1://todo...}\n}"}, 14 | { "trigger":"onUpdate\tlifecycle com", "contents":"onUpdate:function(){\n\t${1://todo...}\n}"}, 15 | { "trigger":"onBeforeUpdate\tlifecycle com", "contents":"onBeforeUpdate:function(changes){\n\t${1://todo...}\n}"}, 16 | 17 | //directive 18 | { "trigger":"onBind\tlifecycle di", "contents":"onBind:function(vnode,data){\n\t${1://todo...}\n}"}, 19 | { "trigger":"onUpdate\tlifecycle di", "contents":"onUpdate:function(vnode,data){\n\t${1://todo...}\n}"}, 20 | ] 21 | } -------------------------------------------------------------------------------- /IDE plugins/sublime3/impex/impex_scope.sublime-completions: -------------------------------------------------------------------------------- 1 | { 2 | "scope": "text.html.basic source.js.embedded.html meta.function-call.method.js,source.js meta.block.js meta.function-call.method.js", 3 | 4 | "completions": 5 | [ 6 | //component attr 7 | { "trigger":"el\timpex Comp", "contents":"el"}, 8 | { "trigger":"state\timpex Comp", "contents":"state"}, 9 | { "trigger":"refs\timpex Comp", "contents":"refs"}, 10 | { "trigger":"name\timpex Comp", "contents":"name"}, 11 | { "trigger":"parent\timpex Comp", "contents":"parent"}, 12 | { "trigger":"children\timpex Comp", "contents":"children"}, 13 | { "trigger":"setState(\timpex Comp", "contents":"setState(\"${1:path}\",${2:val})"}, 14 | { "trigger":"watch(\timpex Comp", "contents":"watch(\"${1:path}\",function(newVal,oldVal){\n\t${2://todo...}\n})"}, 15 | 16 | //vnode attr 17 | { "trigger":"on(\timpex VNode", "contents":"on(\"${1:type}\",${2:expOrFn})"}, 18 | { "trigger":"setAtt..(\timpex VNode", "contents":"setAttribute(${1:k},${2:v})"}, 19 | { "trigger":"getAtt..(\timpex VNode", "contents":"getAttribute(${1:k})"}, 20 | 21 | //directive data attr 22 | { "trigger":"comp\timpex Di data", "contents":"comp"}, 23 | { "trigger":"value\timpex Di data", "contents":"value"}, 24 | { "trigger":"args\timpex Di data", "contents":"args"}, 25 | { "trigger":"exp\timpex Di data", "contents":"exp"}, 26 | ] 27 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 MrSoya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # impex.js 2 | 3 | > 一个基于数据驱动的组件式web开发引擎 4 | 5 | ## Website 6 | [http://impexjs.org/](http://impexjs.org/) 7 | 8 | ## Demo 9 | 10 | ```html 11 |
12 | {{ 'hello ' + title => cap}} 13 | 14 | {{version}} 15 | 16 |
17 | 37 | ``` 38 | 39 | ## 兼容性 40 | * IE9+ 41 | * FF38+ 42 | * chrome43+ 43 | * safari8+ 44 | * opera31+ 45 | * android4.0+ 46 | * IOS7.1+ 47 | 48 | ## Local Examples 49 | 50 | ``` 51 | 1. npm install http-server -g 52 | 2. http-server ./examples/ -p30760 -o 53 | ``` 54 | 55 | ## License 56 | 57 | Impex基于 [MIT](http://opensource.org/licenses/MIT) 协议发布。请查阅LICENSE文件 58 | -------------------------------------------------------------------------------- /examples/codes/VDOM update with events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 |
10 |
11 |
{{xx}}
12 |
13 |
14 |
click 3434
15 |
16 | 17 |
18 | 19 | 45 | 46 | -------------------------------------------------------------------------------- /examples/codes/VDOM update.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 |

14 | 演示两个相同元素节点更新 15 |

16 | 17 |
18 | 19 |
click me
20 |
click me 2
21 | 22 | 23 |
24 | 25 | 41 | 42 | -------------------------------------------------------------------------------- /examples/codes/calculator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 48 | 49 | 50 | 51 |
52 |
53 | {{exp => format}} 54 |
55 |
56 |
57 | 58 |
59 |
60 |
61 |
62 |
63 | 64 | 65 | 117 | -------------------------------------------------------------------------------- /examples/codes/component - anonymous.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impexui - layout 5 | 6 | 7 | 8 | 9 | 10 | 11 | impex 始终从一个组件开始,无论这个组件是否被注册。下面的代码就是渲染一个匿名组件, 12 | 组件的视图就是document.body。 13 | 匿名组件和命名组件相同,都负责管理自身视图中的数据更新 14 |
15 | 
16 | //渲染匿名组件
17 | impex.create({
18 |     el:'#demo',
19 |     state:{
20 |         name:'impex'
21 |     }
22 | });
23 | 
24 | 
25 |
26 |
27 | name: {{nameStr => cap:1:'23'|json:x}} xx:{{x=>json}} 28 |

29 | 30 |

31 | 32 |
33 |
34 | 35 | 69 | 70 | -------------------------------------------------------------------------------- /examples/codes/component - attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 |

11 | 组件可以接收上级组件传递的参数: 12 |

16 |

17 | 示例:
18 | 19 | <x-comp .content="msg" date="Date.now()" .time="time"> 20 | </x-comp> 21 | 22 |

23 |

24 |
25 |

26 | 父组件: 27 |

content:{{msg}}

28 | 修改组件参数: 29 |

30 | 子组件: 31 | 32 | 33 |

34 |

35 |
36 | 37 | 38 | 71 | 72 | -------------------------------------------------------------------------------- /examples/codes/component - compare.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impexui - layout 5 | 6 | 7 | 8 | 9 | 10 | 11 | 组件对比时的不同更新模式 12 |
13 |
14 | 属性不同时,组件会更新 15 | 16 | <div .style="{colour:color}">{ {msg} }</div> 17 | 18 | 19 | 20 | 21 |
22 |
23 | slot不同时,组件会删除重建 24 | 25 | ,以及slot内的一段文字 26 | 27 | 28 | ,以及slot内的另一段文字 29 | 30 | 31 |
32 |
33 | 34 | 35 | 65 | 66 | -------------------------------------------------------------------------------- /examples/codes/component - computedstate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 | 打开控制台,查看变更记录 14 |
15 |

16 | x({{x}}) + y({{y}})+ b({{b}}) = {{z+b}} 17 |

18 |
19 | x: 20 |
21 |
22 | y: 23 |
24 |
25 | b: 26 |
27 |
28 | 29 | 30 | 49 | 50 | -------------------------------------------------------------------------------- /examples/codes/component - create.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 14 | 15 | 16 |
17 | 鼠标放到这里就会出现提示框 20 |
21 | 22 | 52 | 53 | -------------------------------------------------------------------------------- /examples/codes/component - cross level var.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | model -> view 13 |
14 | 15 | store.value in x-a: {{store.value}}
16 | rootV : {{rootV}} 17 | 18 | store.value in x-b: {{store.value}}
19 | rootV : {{rootV}} 20 | 21 | store.value in x-c: {{store.value}}
22 | rootV : {{rootV}} 23 |
24 |
25 |
26 | 27 | 28 |
29 | 30 | 74 | 75 | -------------------------------------------------------------------------------- /examples/codes/component - event - keyboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 33 | 34 | 35 |
36 | 40 | 41 | 45 | 46 | 51 |
52 | 53 | 54 | 84 | 85 | -------------------------------------------------------------------------------- /examples/codes/component - event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impexui - layout 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | impex可以直接渲染命名组件 14 |
15 | 
16 |     <x-demo id="demo"></x-demo>
17 |     //渲染命名组件
18 |     impex.create({
19 |         el:'#demo',
20 |         ...
21 | 
22 | 
23 |
24 | 25 | 26 | 27 |
28 | 43 | 44 | -------------------------------------------------------------------------------- /examples/codes/component - extends.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | extends 10 | 11 |
12 | 13 | 51 | 52 | -------------------------------------------------------------------------------- /examples/codes/component - is.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |

14 | x-check: 15 |

16 | 17 | 18 | dynamic: 19 |
20 | 21 | 47 | 48 | -------------------------------------------------------------------------------- /examples/codes/component - lifecycle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | impex组件生命周期包括:
9 | 创建——>编译——>显示——>(状态变更——>)销毁 四个阶段 10 | 11 | 12 |
13 | 14 | 15 | 16 |
17 |

18 |
19 | 20 | 94 | 95 | -------------------------------------------------------------------------------- /examples/codes/component - mixins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | mixins 10 | 11 | {{info()}} 12 | 13 |
14 | 15 | 43 | 44 | -------------------------------------------------------------------------------- /examples/codes/component - named.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impexui - layout 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | lastTextNode:{{end}} 22 |
23 | 64 | 65 | -------------------------------------------------------------------------------- /examples/codes/component - nexttick.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | next tick 10 |
11 | {{name}} 12 |
13 | 14 |
15 | 16 | 38 | 39 | -------------------------------------------------------------------------------- /examples/codes/component - parent-children.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | model -> view 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 64 | 65 | -------------------------------------------------------------------------------- /examples/codes/component - props.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |

9 | 组件参数可以设置类型和是否必须,如果不满足条件会报错 10 |

11 |
12 | 13 |
14 | 15 | 16 | 按F12打开控制台,会看到error信息 17 | 18 | 19 | 51 | 52 | -------------------------------------------------------------------------------- /examples/codes/component - this.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 13 | 14 | 15 | 在一个组件的视图中的this,永远指向视图所在的组件 16 | 24 |
25 | this.$name: {{$name}} 26 | 27 | 31 | this.$name: {{$name}} click 32 | 33 | this.$name: {{$name}} 34 | 36 | this.$name: {{$name}} click 37 | 38 | 39 | 40 |
41 | 42 | 104 | 105 | -------------------------------------------------------------------------------- /examples/codes/component - watch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | watch用来对组件数据的特定表达式进行监控 10 |

11 | a.b.x:{{a.b.x}} 12 |

13 |

14 | b:{{b}} 15 |

16 |

17 | a.b.c.list:{{a.b.c['list']}} 18 |

19 |

20 | x:{{x}} 21 |

22 | 23 |
24 | 25 | 69 | 70 | -------------------------------------------------------------------------------- /examples/codes/debug - stack.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | model -> view 13 |
14 |
33
15 | 16 | 111 17 | store.value in x-a: {{store.value}}
18 | rootV : {{rootV}} 19 | {{1212 => xx}} {{1212 => yy|xx}} 20 | 21 | store.value in x-b: {{store.value}}
22 | rootV : {{rootV}} 23 | 24 | store.value in x-c: {{store.value}}
25 | rootV : {{rootV}} 26 |
27 |
28 |
29 | 30 | 31 |
32 | 33 | 78 | 79 | -------------------------------------------------------------------------------- /examples/codes/delimiters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impexui - layout 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

13 | 表达式边界符修改: 14 | {{ }} -> {# #} 15 |

16 | 17 |

18 | 修改值: 19 | {# x #} -> @ 20 |

21 | 22 | 23 |
24 | 
25 | impex.config({
26 |     delimiters:['{#','#}']
27 | });
28 | 
29 | //渲染
30 | impex.render(document.body,{
31 |     state:{
32 |         x:'@'
33 |     }
34 | });
35 | 
36 | 
37 | 38 |
39 | 40 | -------------------------------------------------------------------------------- /examples/codes/directive - bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 15 | 16 | 17 | 18 |
19 | 绑定title属性 20 |

21 | Hello impex !
website:{{address}}
22 |
23 | change address: 24 |

25 | 26 | 绑定style属性(style属性支持x-style指令相同语法) 27 |

28 |

31 | style here 32 |
33 |

34 | 35 | 绑定class属性(class属性支持x-class指令相同语法) 36 |

37 |

40 | class here 41 |
42 |

43 |
44 | 45 | 46 | 60 | 61 | -------------------------------------------------------------------------------- /examples/codes/directive - class.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 | x-class支持不同的写法: 23 | 34 | 35 |

style

36 | 37 | .c1{ 38 | color:red; 39 | } 40 | .c2{ 41 | font-size:20px; 42 | } 43 | .c3{ 44 | font-style: italic; 45 | } 46 | 47 | 48 |
49 |

50 |

demo 1

51 | 52 | <div x-class="'c1 c2 c3'"> 53 | class 54 | </div> 55 | 56 |
57 | class 58 |
59 |

60 |

61 |

demo 2

62 | 63 | <div x-class="clsAry"> 64 | class 65 | </div> 66 | 67 |
68 | class 69 |
70 | 73 | 76 | 79 |

80 |

81 |

demo 3

82 | 83 | <div x-class="{'c1':addC1,'c2':addC2,'c3':addC3}"> 84 | class 85 | </div> 86 | 87 |
88 | class 89 |
90 | 91 | 92 | 93 |

94 |
95 | 96 | 116 | 117 | -------------------------------------------------------------------------------- /examples/codes/directive - cloak.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | x-cloak用于屏蔽指定渲染模块: 17 | 18 |
19 |

20 | 看不到的内容 21 |

22 |
23 | 24 | 25 | 34 | 35 | -------------------------------------------------------------------------------- /examples/codes/directive - elseif.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 | more than 4 24 | less then 4 25 | equal to 4 26 |
27 |

28 | x>4: 29 |

30 |
31 | 32 | 51 | 52 | -------------------------------------------------------------------------------- /examples/codes/directive - event - bubbles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 19 | 20 | 21 | 阻止事件冒泡,除调用原生方法外,还可以使用事件修饰符.stop 22 |
23 | 27 |
28 | click me 29 | 30 |
31 | click me 32 |
33 |
34 |
35 | 36 | 37 | 58 | 59 | -------------------------------------------------------------------------------- /examples/codes/directive - event - keyboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 33 | 34 | 35 |
36 | 39 | 40 | 45 |
46 | 47 | 48 | 70 | 71 | -------------------------------------------------------------------------------- /examples/codes/directive - event - mouseenter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 35 | 36 | 37 |
38 |
42 | parent 43 |
46 | child 47 |
48 | grandchildren 49 |
50 |
51 |
52 | 53 |
54 | neighbor 55 |
56 | 57 | 58 |

59 | {{item}} 60 |

61 |
62 | 63 | 64 | 82 | 83 | -------------------------------------------------------------------------------- /examples/codes/directive - event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 打开控制台查看 10 | 15 |
16 | 17 | 18 | 48 | 49 | -------------------------------------------------------------------------------- /examples/codes/directive - for - component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 | 11 |
12 | mod: 13 | 14 |
15 |
16 |
17 |
18 | 19 | 67 | 68 | -------------------------------------------------------------------------------- /examples/codes/directive - for - template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 | 11 |
12 | mod: 13 | 18 |
19 | 20 | 35 | 36 | -------------------------------------------------------------------------------- /examples/codes/directive - for - template2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 |

11 | 12 | for 允许同时对多个元素进行循环,比如带分割线的区域 13 |

14 |

15 |

16 |             
17 |                 <template x-for="groups as g">
18 |                     <a >
19 |                         {{g.title}}  <span x-for="[1,2,3,4,5,6] as i">{{i}}</span>
20 |                     </a>
21 |                     <b x-if="$index % 2 == 0">
22 |                         {{g.desc}}
23 |                     </b>
24 |                     <br>
25 |                 </template>
26 |             
27 |             
28 |

29 | 30 | 31 | 32 |
33 | 42 |
43 | 44 | 68 | 69 | -------------------------------------------------------------------------------- /examples/codes/directive - for - to.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 | 11 | 12 |
13 | 1- 14 | 19 |
20 | 39 | 40 | -------------------------------------------------------------------------------- /examples/codes/directive - form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 19 | 20 | 21 | 22 | 23 |
24 |

25 |

26 | {{name}} {{v}} 27 |

28 |

29 | {{desc}} 30 |

31 |

32 | it's {{features}} 33 |

34 |

35 | made by {{author}} 36 | ,{{sex}} 37 |

38 |

39 | and {{others}} 40 |

41 |

42 |

43 | name: 44 |

45 |

46 | version: 47 |

48 |

49 | features: 50 | 53 | 56 | 59 | 60 |

61 |

62 | author: 63 | 66 | 69 | 72 |

73 |

74 | sex: 75 | 79 |

80 |

81 | desc: 82 | 85 |

86 |

87 | others: 88 | 92 |

93 |
94 | 117 | 118 | -------------------------------------------------------------------------------- /examples/codes/directive - html - for.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 增加 15 | 16 |
17 | 67 | 68 | -------------------------------------------------------------------------------- /examples/codes/directive - html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 |
10 |
11 |

12 | title1: 修改html中的变量值 13 |

14 |

15 | html2: 16 | 修改html内容 17 |

18 |
19 | 20 | 32 | 33 | -------------------------------------------------------------------------------- /examples/codes/directive - if - template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 |
14 | 22 | 28 | 34 | size: 35 |
36 | 37 | 47 | 48 | -------------------------------------------------------------------------------- /examples/codes/directive - if test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 单行数据 13 |
14 | 22 | 23 |
24 | 25 | 40 | 41 | -------------------------------------------------------------------------------- /examples/codes/directive - if.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 | true 24 | false 25 |
26 | x>4: 27 |
28 | 29 | 48 | 49 | -------------------------------------------------------------------------------- /examples/codes/directive - model - attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | Content1 : {{value1}} {{typeof value1}}
10 | Content2 : {{value2}} {{typeof value2}} 11 |

12 | debounce & number input : 13 |

14 |

15 | debounce input : 16 |

17 |
18 | 19 | 20 | 32 | 33 | -------------------------------------------------------------------------------- /examples/codes/directive - pre.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | x-pre指令可以让编译器把节点内部所有内容当作文本处理 10 | 11 |
12 | 13 |
14 | 使用了x-pre指令{{ exp }} 15 | {{msg}} 16 | {{msg2}} 17 | 18 | {{23232}} 19 |
20 |
21 |
22 | 未使用x-pre指令 23 | {{msg}} 24 | {{msg2}} 25 |
26 |
27 | 28 | 42 | 43 | -------------------------------------------------------------------------------- /examples/codes/directive - show on component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 34 | 35 | -------------------------------------------------------------------------------- /examples/codes/directive - show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 18 | 19 | 20 |
21 |

x > 4 true

22 |
23 |

x < 4 true

24 |
25 | x: 26 |
27 | 28 | 41 | 42 | -------------------------------------------------------------------------------- /examples/codes/directive - style.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | x-style支持不同的写法: 12 | 26 | 27 | 28 |
29 |

30 |

demo 1

31 | 32 | <div x-style=" {'color':color,'font-size':size}"> 33 | ... 34 | </div> 35 | 36 |
37 | color:{{color}} size:{{size}} 38 |
39 | color: 40 | size: 41 |

42 |

43 |

demo 2

44 | 45 | <div x-style=" style"> 46 | ... 47 | </div> 48 | 49 |
50 | {{style => json}} 51 |
52 | style.color: 53 | style.fontSize: 54 |

55 |

56 |

demo 3

57 | 58 | <div x-style=" css"> 59 | ... 60 | </div> 61 | 62 |
63 | {{css => json}} 64 |
65 | css: 66 |

67 |
68 | 69 | 86 | 87 | -------------------------------------------------------------------------------- /examples/codes/filter - chain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | edge here::{{ ' HELLO IMPEX ' + version => trim:'side' |lower |cap:1}}::here edge 10 |
11 | 12 | 13 | 38 | 39 | -------------------------------------------------------------------------------- /examples/codes/filter - currency.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 |
10 | {{money => currency:'¥':len}} 11 |
12 | {{money => currency:'$':3}} 13 |
14 | {{money => currency:'€':4}} 15 |
16 | {{money => inScope}} 17 |
18 | 19 | 49 | 50 | -------------------------------------------------------------------------------- /examples/codes/filter - for.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 |
11 |
12 | {{$index}} {{v => json}} 13 |
14 |

15 | name: 16 |

17 |
18 | 19 | 20 | 21 | 42 | 43 | -------------------------------------------------------------------------------- /examples/codes/global component ref.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 15 | 16 | 17 |
18 | 全局变量注册 19 | 2222222222222222 20 | 111111111 21 |
22 | 23 | 47 | 48 | -------------------------------------------------------------------------------- /examples/codes/global event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 |
14 | 15 |

16 | 17 | 18 |

19 |
20 | 21 | 22 | 75 | 76 | -------------------------------------------------------------------------------- /examples/codes/global var.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 12 | 13 | 14 |
15 | 16 | 19 | 20 | {{i}} 21 | 22 | 23 | 24 | 25 | 28 | 29 | 32 | 33 |
34 | 35 | 36 | 37 | 76 | 77 | -------------------------------------------------------------------------------- /examples/codes/html-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 | 14 | 24 | 25 | -------------------------------------------------------------------------------- /examples/codes/nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 表格 10 | 11 | 12 | 15 | 16 |
13 | {{k}} : {{row[col['name']]}} : {{info[row[col.name]].msg}} 14 |
17 |

18 | div 19 |

20 |
21 | 22 | {{k}} : {{row[col['name']]}} : {{info[row[col.name]].msg}} 23 | 24 |
25 |
26 | 27 | 28 | 29 | 81 | 82 | -------------------------------------------------------------------------------- /examples/codes/number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | Number:响应鼠标滚动 14 |
15 | 16 | 17 | 63 | 64 | -------------------------------------------------------------------------------- /examples/codes/observe-array.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{ary=>json}} 14 |

15 | 计算属性:{{x}} 16 |

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | bug原因:对比VNODE时,如果是组件直接返回了。而组件只更新指令,对于没有指令的组件输入参数就无法更新了. 28 | 73 | 74 | -------------------------------------------------------------------------------- /examples/codes/observe-object.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{obj => json}} 14 |

15 | 计算属性:{{x}} 16 | 17 |

18 | 19 | 20 | 21 | 22 |
23 | bug原因:对比VNODE时,如果是组件直接返回了。而组件只更新指令,对于没有指令的组件输入参数就无法更新了. 24 | 62 | 63 | -------------------------------------------------------------------------------- /examples/codes/performence-nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | {{k / x * i}} 21 | 22 |
23 |
24 | 25 | 26 | 49 | 50 | -------------------------------------------------------------------------------- /examples/codes/performence-parser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 | 11 | 显示解析性能 12 |
13 | 14 |
15 | 16 | 17 | 45 | 46 | -------------------------------------------------------------------------------- /examples/codes/plugin - event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 使用插件实现pointer事件 10 | 13 | 16 |
17 | 18 | 19 | 50 | 51 | -------------------------------------------------------------------------------- /examples/codes/plugin - store.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 使用插件实现store的所有属性注入组件state 10 | 11 | 12 | 13 |

in x-b {{value}}

14 |
15 |

$store.value in x-a {{$store.value}}

16 |

value in x-a {{value}}

17 |
18 | 19 |

in x-c {{$store.value}}

20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 87 | 88 | -------------------------------------------------------------------------------- /examples/codes/propsChange.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 |

10 | 在属性变更回调中如果覆盖propsChange回调,就需要自己实现更新 11 | 放开代码中的注释,尝试编写一个手动更新 12 |

13 | 14 | 15 | 16 | 17 | 修改组件参数: 18 | 19 |
20 | 21 | 22 | 23 | 52 | 53 | -------------------------------------------------------------------------------- /examples/codes/ref.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 演示ref属性的使用 9 |
10 |
11 | 这是一个被ref引用的DOM节点 12 |
13 | 14 | 这是一个被ref引用的组件节点 15 | 16 |
17 | 18 | 34 | 35 | -------------------------------------------------------------------------------- /examples/codes/select.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 13 | 14 | 15 | 37 | 38 | -------------------------------------------------------------------------------- /examples/codes/slot component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 | 9 |
10 | 11 |
head {{no}}
12 |
13 | body 14 | 15 |
16 | 17 |
18 | 19 | foot 20 | 21 | 22 | head 23 | 24 | 25 |
26 | 27 | 53 | 54 | -------------------------------------------------------------------------------- /examples/codes/slot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 | 14 |
15 | 16 | name 17 | 13 18 | 19 | invalid slot 20 | 21 | 来自slot的内容 22 | 13 23 | 24 | 25 | 26 |
27 | 28 | 54 | 55 | -------------------------------------------------------------------------------- /examples/codes/store.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 11 | 12 | 13 |
14 |

15 | computeState:
16 | a({{a}}) + b({{b}}) 17 |

18 | 19 | storeX({{store.x}}) + storeY({{store.y}}) 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 77 | 78 | -------------------------------------------------------------------------------- /examples/codes/test case - node update.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 7 | 8 |
9 | 10 | 12 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 32 | 33 | 111 34 | 222 35 | 333 36 | 37 | 38 | 39 | 40 | 41 | 44 |
45 | 46 | 74 | 75 | -------------------------------------------------------------------------------- /examples/codes/updateprop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Impex Demo 5 | 6 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 |

17 | items[0].name: 18 |

19 |

20 | items[0].children[0].name: 21 |

22 |
23 | 24 | 77 | 78 | -------------------------------------------------------------------------------- /examples/codes/wishlist/css/main.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-size: 1rem; 3 | font-family: "Microsoft YaHei",arial,sans-serif; 4 | background-color: #fcfcfc; 5 | margin: 0; 6 | color: #333; 7 | position: absolute; 8 | width: 100%; 9 | height: 100%; 10 | } 11 | 12 | #entry{ 13 | position: absolute; 14 | width: 100%; 15 | height: 100%; 16 | display: flex; 17 | flex-direction: column; 18 | } 19 | 20 | ul{ 21 | list-style: none; 22 | padding: 0; 23 | } 24 | 25 | /* headers */ 26 | header{ 27 | background-color: #fff; 28 | padding-top: 1.5rem; 29 | box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.1); 30 | } 31 | header h2{ 32 | text-align: center; 33 | font-weight: 300; 34 | margin: 0 0 .5rem 0; 35 | } 36 | header ul{ 37 | display: flex; 38 | margin-bottom: 0; 39 | } 40 | header ul li{ 41 | color: #aaa; 42 | flex: 1; 43 | text-align: center; 44 | padding: 5px 1rem; 45 | transition: all .5s; 46 | } 47 | header ul li.active{ 48 | color: #666; 49 | border-bottom: 1px solid #2285bf; 50 | box-shadow: 0 10px 16px 0 rgba(34, 133, 191, .1); 51 | } 52 | 53 | 54 | /* main */ 55 | main{ 56 | flex: 1; 57 | overflow: auto; 58 | padding: .5rem 0 5rem; 59 | } 60 | main hr{ 61 | border-color: #f0f0f0; 62 | border-style: solid; 63 | } 64 | 65 | .addbtn{ 66 | position: fixed; 67 | right: 1rem; 68 | bottom: 1rem; 69 | border-radius: 3rem; 70 | color: #fff; 71 | text-align: center; 72 | font-size: 2rem; 73 | width: 3rem; 74 | height: 3rem; 75 | background-color: #2285bf; 76 | box-shadow: 0 0 16px 0 rgba(34, 133, 191, .5); 77 | z-index: 9; 78 | transition: all .2s; 79 | } 80 | .addbtn.close{ 81 | width: 0; 82 | height: 0; 83 | overflow: hidden; 84 | } 85 | 86 | .panel{ 87 | background-color: #f0f0f0; 88 | padding:.5rem; 89 | padding-right: 0; 90 | display: flex; 91 | border: 1px solid #eee; 92 | border-width: 1px 0 0 0; 93 | position: fixed; 94 | width: 100%; 95 | top: 100%; 96 | transition: all .3s; 97 | z-index: 999; 98 | } 99 | .panel.open{ 100 | top: auto; 101 | bottom: 0; 102 | } 103 | .panel input{ 104 | font-size: 1rem; 105 | background: #fff; 106 | border: none; 107 | padding: .5rem 0 .5rem .5rem; 108 | } 109 | .panel input[name="title"]{ 110 | flex: 1; 111 | } 112 | .panel input[name="cost"]{ 113 | width: 4rem; 114 | } 115 | .panel button{ 116 | background: #f0f0f0; 117 | border:none; 118 | font-size: 1rem; 119 | width: 3rem; 120 | } 121 | 122 | .x-wish{ 123 | background-color: #fff; 124 | width: 96%; 125 | margin: 1rem 0 1rem 2%; 126 | border:1px solid #eee; 127 | border-top: none; 128 | padding: .5rem 0; 129 | min-height: 4rem; 130 | vertical-align: middle; 131 | position: relative; 132 | display: flex; 133 | transition: all .2s; 134 | } 135 | .progress{ 136 | position: absolute; 137 | top: 0; 138 | left: 0; 139 | background-color: rgba(111, 111, 255, 0.1); 140 | height: 100%; 141 | z-index: 0; 142 | transition: all .2s; 143 | } 144 | .target{ 145 | position: absolute; 146 | left: 0; 147 | top: 0%; 148 | margin: 0; 149 | width: 100%; 150 | display: flex; 151 | z-index: -1; 152 | opacity: 0; 153 | transition: all .2s; 154 | } 155 | 156 | .x-wish.show{ 157 | box-shadow: 0 0px 16px 0 rgba(0, 67, 151, 0.1); 158 | margin-bottom: 3.5rem; 159 | } 160 | .x-wish.show .target{ 161 | top: 100%; 162 | opacity: 1; 163 | box-shadow: 0 2px 16px 0 rgba(0, 67, 151, 0.1); 164 | z-index: 1; 165 | } 166 | .x-wish.show .progress{ 167 | height: 0; 168 | top: 100%; 169 | } 170 | .target li{ 171 | flex: 1; 172 | border: 1px solid #eee; 173 | padding: .5rem 0; 174 | text-align: center; 175 | background-color: #fff; 176 | border-right: none; 177 | } 178 | .target li.passed{ 179 | background-color: rgba(111, 111, 255, 0.1); 180 | } 181 | .target li:first-child{ 182 | border-left: none; 183 | } 184 | .title{ 185 | flex: 1; 186 | line-height: 4rem; 187 | margin-left: .5rem; 188 | z-index: 1; 189 | } 190 | .cost{ 191 | color: #ff5858; 192 | font-size: 1.2rem; 193 | font-style: normal; 194 | line-height: 4rem; 195 | position: absolute; 196 | right: .5rem; 197 | z-index: 1; 198 | } 199 | 200 | .done{ 201 | position: absolute; 202 | bottom: 0; 203 | left: 0; 204 | width: 100%; 205 | color: #ccc; 206 | text-align: center; 207 | } -------------------------------------------------------------------------------- /examples/codes/wishlist/data.js: -------------------------------------------------------------------------------- 1 | [ 2 | {id:1,title:'买一台Switch',cost:3000,done:false,progress:40}, 3 | {id:2,title:'走遍五岳',cost:10000,done:false,progress:20}, 4 | {id:3,title:'全国自驾游',cost:20000,done:false,progress:0}, 5 | {id:4,title:'骑行1000km',cost:5000,done:false,progress:0} 6 | ] -------------------------------------------------------------------------------- /examples/codes/wishlist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Wish List 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

wish list

14 | 18 |
19 |
20 |
21 | 27 |
28 |
29 | 35 |
36 |
37 | 38 |
39 | 40 | 41 | 42 |
43 | + 44 |
45 | 46 | 47 | 48 | 113 | 114 | -------------------------------------------------------------------------------- /examples/codes/wishlist/js/components.js: -------------------------------------------------------------------------------- 1 | impex.component("x-wish",{ 2 | template:` 3 |
4 |
5 | 6 | {{title}} 7 | 8 | {{cost=>formatRMB}} 9 |
已在 {{time => formatDate}} 达成
10 | 13 |
`, 14 | state:function(){ 15 | var props = this.$props; 16 | return { 17 | progress:props.progress||0, 18 | show:false, 19 | time:props.time||'', 20 | done:props.done 21 | }; 22 | }, 23 | created:function(argument) { 24 | this.$setState(this.$props); 25 | }, 26 | props:{ 27 | title:{ 28 | type:'string', 29 | require:true 30 | }, 31 | cost:{ 32 | type:'number', 33 | require:true 34 | } 35 | }, 36 | setProgress : function(prog){ 37 | this.progress = prog; 38 | if(prog == 100){ 39 | this.$emit('done',this.id); 40 | } 41 | this.$emit('progress',this.id,prog); 42 | }, 43 | open:function() { 44 | if(this.done)return; 45 | 46 | var lastShow = this.$root.showWish; 47 | this.$root.showWish = this; 48 | if(lastShow == this){ 49 | if(this.show){ 50 | this.show = false; 51 | this.close(); 52 | }else{ 53 | this.show = true; 54 | } 55 | return ; 56 | } 57 | this.show = true; 58 | if(lastShow && lastShow.$id)lastShow.close(); 59 | }, 60 | close:function() { 61 | this.show = false; 62 | } 63 | }); -------------------------------------------------------------------------------- /examples/codes/wishlist/js/filters.js: -------------------------------------------------------------------------------- 1 | impex.filter('formatRMB',function(value){ 2 | var pair = (value+"").split('.'); 3 | var inte = pair[0].replace(/\s/g,''); 4 | var integer = ''; 5 | var delta = 0; 6 | for(var i=inte.length;i--;){ 7 | integer = inte[i] + integer; 8 | delta++; 9 | if(delta%3==0){ 10 | integer = ','+integer; 11 | delta = 0; 12 | } 13 | } 14 | return '¥' + integer.replace(/^,/,''); 15 | }); 16 | 17 | impex.filter('formatDate',function(value){ 18 | var d = new Date(); 19 | d.setTime(value); 20 | var mon = d.getMonth()+1+''; 21 | if(mon.length<2)mon = '0'+mon; 22 | var date = d.getDate()+''; 23 | if(date.length<2)date = '0'+date; 24 | return d.getFullYear()+'-'+mon+'-'+date; 25 | }); -------------------------------------------------------------------------------- /examples/lib/fontawesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/examples/lib/fontawesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /examples/lib/fontawesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/examples/lib/fontawesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /examples/lib/fontawesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/examples/lib/fontawesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /examples/lib/fontawesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/examples/lib/fontawesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /examples/lib/fontawesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrSoya/impex/ac9c2f41ea18ff5eeba8c34198e61384c6265e67/examples/lib/fontawesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /examples/lib/impex/impex.ext.loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * loadable提供一个基于ajax的组件加载接口,可以简化组件加载写法 3 | * 4 | * 兼容性:IE 9+ 5 | */ 6 | !function(g){ 7 | /** 8 | * 加载指定url 9 | * @param {[type]} url [description] 10 | * @return {Function} 返回一个符合promise接口的回调函数 11 | */ 12 | g.loadable = function(url) { 13 | // var fn = new Function('resolve','reject','ajax("'+url+'",resolve,reject)'); 14 | return function(resolve,reject) { 15 | ajax(url,resolve,reject); 16 | }; 17 | } 18 | 19 | function ajax(url,resolve,reject) { 20 | var xhr = new XMLHttpRequest(); 21 | xhr.open('get',url,true); 22 | xhr.onerror = reject; 23 | xhr.__resolve = resolve; 24 | if(xhr.onload === null){ 25 | xhr.onload = onload; 26 | }else{ 27 | xhr.onreadystatechange = onload; 28 | } 29 | xhr.url = url; 30 | xhr.send(null); 31 | } 32 | 33 | function onload(){ 34 | if(this.status===0 || //local 35 | ((this.status >= 200 && this.status <300) || this.status === 304) ){ 36 | var txt = this.responseText; 37 | this.__resolve(txt); 38 | } 39 | } 40 | 41 | }(window); 42 | -------------------------------------------------------------------------------- /examples/lib/impex/impex.ext.store.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Store是一个基于impex的flux解决方案。用于处理大量共享状态需要交互的场景 3 | */ 4 | !function(impex){ 5 | 6 | var store_counter = 0; 7 | 8 | /** 9 | * @class impex.Store是一个基于impex的flux解决方案。用于处理大量共享状态需要交互的场景 10 | * @param {Object} data 构造参数 11 | * @param {Object} [actions] store中的逻辑实现 12 | * @param {Object} [state] store中的存储 13 | */ 14 | function Store(data){ 15 | this._uid = 'S_'+store_counter++; 16 | /** 17 | * 数据 18 | * @type {Object} 19 | */ 20 | this.state = {}; 21 | 22 | this.__subscribeMap = {}; 23 | //{state:[comp,compState]} 24 | this.__noticeMap = {}; 25 | //current action 26 | this.__action; 27 | 28 | var keys = Object.keys(data); 29 | for (var i=keys.length;i--;) { 30 | var k = keys[i]; 31 | this[k] = data[k]; 32 | } 33 | 34 | if(!this.actions)this.actions = {}; 35 | 36 | if(this.state instanceof Function){ 37 | this.state = this.state.call(ins); 38 | } 39 | 40 | this.state = impex._Observer.observe(this.state,this); 41 | } 42 | 43 | Store.prototype = { 44 | /** 45 | * 监听action执行 46 | * @param {String} type action type 47 | * @param {Function | Component} listener 监听回调或组件引用 48 | * @param {Object} context 参数/回调函数所属上下文。可以是组件、指令或者任何对象 49 | * 如果是组件引用,系统会自动更新组件对应由action执行引起的state变动 50 | */ 51 | subscribe:function(type,listener,context){ 52 | var ts = type.replace(/\s+/mg,' ').split(' '); 53 | for(var i=ts.length;i--;){ 54 | var t = ts[i]; 55 | var listeners = this.__subscribeMap[t]; 56 | if(!listeners)listeners = this.__subscribeMap[t] = []; 57 | 58 | listeners.push([listener,context]); 59 | }//end for 60 | }, 61 | /** 62 | * 解除监听action执行 63 | * @param {String} [type] action type。如果是空,删除所有监听 64 | * @param {Function | Component} [listener] 监听回调或组件引用。如果是空,删除指定分类监听 65 | */ 66 | unsubscribe:function(type,listener){ 67 | var types = null; 68 | if(!type){ 69 | types = Object.keys(this.__subscribeMap); 70 | }else{ 71 | types = type.replace(/\s+/mg,' ').split(' '); 72 | } 73 | 74 | for(var i=types.length;i--;){ 75 | var listeners = this.__subscribeMap[types[i]]; 76 | if(listeners){ 77 | var toDel = []; 78 | for(var j=listeners.length;j--;){ 79 | if(listener?listeners[j][0] === listener:true){ 80 | toDel.push(listeners[j]); 81 | } 82 | } 83 | toDel.forEach(function(listener){ 84 | var index = listeners.indexOf(listener); 85 | listeners.splice(index,1); 86 | }); 87 | } 88 | } 89 | }, 90 | /** 91 | * 触发action 92 | * @param {String} [type] action type 93 | * @param {...} [var] 可变参数,传递给action回调 94 | */ 95 | commit:function(){ 96 | var action = arguments[0]; 97 | 98 | var params = []; 99 | for(var i=1;i=b.outerHeight()?k=!0:(c.stop(!0, 11 | !0).fadeIn("fast"),a.railVisible&&m.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(B=setTimeout(function(){a.disableFadeOut&&r||y||z||(c.fadeOut("slow"),m.fadeOut("slow"))},1E3))}var r,y,z,B,A,u,l,C,k=!1,b=e(this);if(b.parent().hasClass(a.wrapperClass)){var q=b.scrollTop(),c=b.siblings("."+a.barClass),m=b.siblings("."+a.railClass);x();if(e.isPlainObject(f)){if("height"in f&&"auto"==f.height){b.parent().css("height","auto");b.css("height","auto");var h=b.parent().parent().height();b.parent().css("height", 12 | h);b.css("height",h)}else"height"in f&&(h=f.height,b.parent().css("height",h),b.css("height",h));if("scrollTo"in f)q=parseInt(a.scrollTo);else if("scrollBy"in f)q+=parseInt(a.scrollBy);else if("destroy"in f){c.remove();m.remove();b.unwrap();return}n(q,!1,!0)}}else if(!(e.isPlainObject(f)&&"destroy"in f)){a.height="auto"==a.height?b.parent().height():a.height;q=e("
").addClass(a.wrapperClass).css({position:"relative",overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden", 13 | width:a.width,height:a.height});var m=e("
").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=e("
").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible?"block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius, 14 | WebkitBorderRadius:a.borderRadius,zIndex:99}),h="right"==a.position?{right:a.distance}:{left:a.distance};m.css(h);c.css(h);b.wrap(q);b.parent().append(c);b.parent().append(m);a.railDraggable&&c.bind("mousedown",function(a){var b=e(document);z=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);n(0,c.position().top,!1)});b.bind("mouseup.slimscroll",function(a){z=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll", 15 | function(a){a.stopPropagation();a.preventDefault();return!1});m.hover(function(){w()},function(){p()});c.hover(function(){y=!0},function(){y=!1});b.hover(function(){r=!0;w();p()},function(){r=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(A=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&&(n((A-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),A=b.originalEvent.touches[0].pageY)}); 16 | x();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),n(0,!0)):"top"!==a.start&&(n(e(a.start).position().top,null,!0),a.alwaysVisible||c.hide());window.addEventListener?(this.addEventListener("DOMMouseScroll",v,!1),this.addEventListener("mousewheel",v,!1)):document.attachEvent("onmousewheel",v)}});return this}});e.fn.extend({slimscroll:e.fn.slimScroll})})(jQuery); -------------------------------------------------------------------------------- /examples/themes/default.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | margin: 0; 4 | padding: 0; 5 | font-size: 16px !important; 6 | line-height: 1; 7 | background: #fafafa; 8 | font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; } 9 | 10 | code { 11 | padding: .2rem .4rem; 12 | font-size: 90%; 13 | color: #bd4147; 14 | background-color: #f7f7f9; 15 | border-radius: .25rem; 16 | line-height: 1.5; } 17 | 18 | iframe { 19 | width: 100%; 20 | height: 100%; } 21 | 22 | ul, ol { 23 | list-style: none; 24 | margin: 0; 25 | padding: 0px; } 26 | 27 | .impex-layout { 28 | height: 100%; 29 | width: 100%; 30 | display: block; 31 | overflow: hidden; } 32 | .impex-layout header { 33 | position: fixed; 34 | right: 0; 35 | left: 0; 36 | z-index: 9; 37 | font-size: 2rem; 38 | background-color: #000; 39 | color: #fff; 40 | padding: 1rem; } 41 | .impex-layout .sidebar { 42 | white-space: nowrap; 43 | width: 15rem; 44 | position: fixed; 45 | border-right: 1px solid #ddd; 46 | float: left; 47 | height: 100%; 48 | overflow: hidden; 49 | transition: all .2s; } 50 | .impex-layout .sidebar .scrollpane { 51 | width: 100%; 52 | height: calc(100% - 6rem); 53 | padding-top: 6rem; 54 | padding-bottom: 0; 55 | overflow: hidden; 56 | position: relative; 57 | background-color: #eee; } 58 | .impex-layout .sidebar .scrollpane .menu-items { 59 | margin-left: .5rem; } 60 | .impex-layout .sidebar .scrollpane .menu-items li.active a { 61 | background: #d2d7dc; 62 | color: #fff !important; } 63 | .impex-layout .sidebar .scrollpane .menu-items a { 64 | color: #666; 65 | padding: .2rem 1rem; 66 | display: block; 67 | text-decoration: none; 68 | line-height: 1.5; } 69 | .impex-layout .sidebar .scrollpane .menu-items a.cate { 70 | outline: none; 71 | width: 80%; 72 | padding: .5rem 2rem .5rem 1rem; 73 | position: relative; 74 | display: inline-block; 75 | margin: .5rem 0; 76 | overflow: hidden; 77 | background: #718a90; 78 | color: #fff; } 79 | .impex-layout .sidebar .scrollpane .menu-items a.link:hover { 80 | background: #fafafa; 81 | text-decoration: underline; 82 | color: #666 !important; } 83 | .impex-layout .sidebar.hidden { 84 | width: 0; 85 | white-space: nowrap; 86 | overflow: hidden; 87 | border-right: none; } 88 | .impex-layout .togglebar { 89 | position: fixed; 90 | display: flex; 91 | flex-direction: row; 92 | top: 4rem; 93 | width: 100%; 94 | background-color: #ddd; 95 | z-index: 9; 96 | border: 1px solid #ddd; 97 | border-width: 1px 0 1px 0; } 98 | .impex-layout .togglebar .menubar { 99 | width: 15rem; 100 | position: relative; 101 | line-height: 1.5; 102 | transition: width .2s; } 103 | .impex-layout .togglebar .menubar .toggler { 104 | position: absolute; 105 | right: .5rem; 106 | line-height: 1.6; 107 | border: 1px solid transparent; 108 | padding: 0 .5rem; } 109 | .impex-layout .togglebar .menubar .toggler:hover { 110 | border: 1px solid #ddd; } 111 | .impex-layout .togglebar .menubar.hidden { 112 | width: 2rem; 113 | white-space: nowrap; 114 | overflow: hidden; } 115 | .impex-layout .togglebar .tabbar { 116 | bottom: -1px; 117 | height: 85%; 118 | flex: 1; 119 | overflow: hidden; 120 | position: relative; } 121 | .impex-layout .togglebar .tabbar .nav { 122 | padding: 5px .2rem; 123 | position: absolute; 124 | left: 0rem; 125 | margin-top: 1px; } 126 | .impex-layout .togglebar .tabbar .nav.right { 127 | left: auto; 128 | right: 1rem; } 129 | .impex-layout .togglebar .tabbar .nav:hover { 130 | border: 1px solid #ddd; } 131 | .impex-layout .togglebar .tabbar .slidebox { 132 | overflow: hidden; 133 | height: 100%; 134 | margin: 0 2rem 0 1rem; } 135 | .impex-layout .togglebar .tabbar ul { 136 | margin: 0; 137 | height: 100%; 138 | white-space: nowrap; 139 | width: 100%; } 140 | .impex-layout .togglebar .tabbar ul li { 141 | display: inline-block; 142 | height: 100%; 143 | margin-top: 1px; 144 | margin-right: .5rem; 145 | border: 1px solid #ddd; } 146 | .impex-layout .togglebar .tabbar ul li a { 147 | text-decoration: none; 148 | padding: 0 1rem; 149 | display: inline-block; 150 | line-height: 1.5; } 151 | .impex-layout .togglebar .tabbar ul li i.fa { 152 | margin-right: .5rem; } 153 | .impex-layout .togglebar .tabbar ul li i.fa:hover { 154 | color: red; } 155 | .impex-layout .togglebar .tabbar ul li.active { 156 | border-bottom: 1px solid #fff; } 157 | .impex-layout .main { 158 | margin-left: 15rem; 159 | padding: 7.5rem 1rem 2rem 1rem; 160 | transition: all .3s; } 161 | .impex-layout .main .panel { 162 | display: none; } 163 | .impex-layout .main .panel.active { 164 | display: block; } 165 | .impex-layout .main.hidden { 166 | margin-left: 0; } 167 | 168 | /*# sourceMappingURL=default.css.map */ 169 | -------------------------------------------------------------------------------- /examples/themes/default.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAIA,UAAS;EACR,MAAM,EAAC,IAAI;EACX,MAAM,EAAC,CAAC;EACR,OAAO,EAAC,CAAC;EACT,SAAS,EAAE,eAAe;EAC1B,WAAW,EAAE,CAAC;EACd,UAAU,EAAC,OAAO;EAClB,WAAW,EAAE,wEACgC;;AAI9C,IAAI;EACH,OAAO,EAAE,WAAW;EACpB,SAAS,EAAE,GAAG;EACd,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,OAAO;EACzB,aAAa,EAAE,MAAM;EACrB,WAAW,EAAC,GAAG;;AAGhB,MAAM;EACL,KAAK,EAAC,IAAI;EACV,MAAM,EAAC,IAAI;;AAGZ,MAAO;EAAC,UAAU,EAAE,IAAI;EAAC,MAAM,EAAC,CAAC;EAAC,OAAO,EAAE,GAAG;;AAG9C,aAAc;EACV,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,MAAM;EAEhB,oBAAM;IACR,QAAQ,EAAE,KAAK;IACZ,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,IAAI;IACf,gBAAgB,EAAE,IAAI;IACtB,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,IAAI;EAGjB,sBAAS;IACL,WAAW,EAAE,MAAM;IACnB,KAAK,EApDG,KAAK;IAqDb,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,cAAc;IAC5B,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,OAAO;IAGnB,kCAAY;MACX,KAAK,EAAE,IAAI;MACX,MAAM,EAAE,iBAA2B;MAEhC,WAAW,EAhEN,IAAI;MAiET,cAAc,EAAE,CAAC;MACpB,QAAQ,EAAE,MAAM;MAChB,QAAQ,EAAE,QAAQ;MAClB,gBAAgB,EAAE,IAAI;MAEtB,8CAAW;QACV,WAAW,EAAE,KAAK;QAClB,0DAAW;UACV,UAAU,EAAE,OAAO;UACnB,KAAK,EAAE,eAAe;QAEvB,gDAAC;UACA,KAAK,EAAE,IAAI;UACX,OAAO,EAAE,UAAU;UACnB,OAAO,EAAE,KAAK;UACd,eAAe,EAAE,IAAI;UACrB,WAAW,EAAE,GAAG;UAEhB,qDAAM;YACL,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,GAAG;YACV,OAAO,EAAE,qBAAqB;YAC9B,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,OAAO;YACnB,KAAK,EAAE,IAAI;UAGZ,2DAAY;YACX,UAAU,EAAE,OAAO;YACnB,eAAe,EAAE,SAAS;YAC1B,KAAK,EAAE,eAAe;EAM9B,6BAAe;IACX,KAAK,EAAE,CAAC;IACR,WAAW,EAAE,MAAM;IACnB,QAAQ,EAAE,MAAM;IAChB,YAAY,EAAC,IAAI;EAGrB,wBAAW;IACV,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,IAAI;IACb,cAAc,EAAE,GAAG;IAChB,GAAG,EAAE,IAAI;IACT,KAAK,EAAE,IAAI;IACX,gBAAgB,EAAE,IAAI;IACtB,OAAO,EAAE,CAAC;IACV,MAAM,EAAC,cAAc;IACrB,YAAY,EAAE,WAAW;IAEzB,iCAAQ;MACP,KAAK,EA5HE,KAAK;MA6HZ,QAAQ,EAAE,QAAQ;MAClB,WAAW,EAAE,GAAG;MAChB,UAAU,EAAE,SAAS;MAErB,0CAAQ;QACP,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,GAAG;QAChB,MAAM,EAAC,qBAAqB;QAC5B,OAAO,EAAE,OAAO;QAEhB,gDAAO;UACN,MAAM,EAAC,cAAc;IAIxB,wCAAe;MACd,KAAK,EAAE,IAAI;MACX,WAAW,EAAE,MAAM;MACnB,QAAQ,EAAE,MAAM;IAGpB,gCAAO;MACH,MAAM,EAAE,IAAI;MACZ,MAAM,EAAE,GAAG;MACX,IAAI,EAAC,CAAC;MACN,QAAQ,EAAE,MAAM;MAChB,QAAQ,EAAE,QAAQ;MAElB,qCAAI;QACH,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,QAAQ;QAClB,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,GAAG;MAEhB,2CAAU;QACT,IAAI,EAAC,IAAI;QACT,KAAK,EAAE,IAAI;MAEZ,2CAAU;QACT,MAAM,EAAC,cAAc;MAGtB,0CAAS;QACR,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,aAAa;MAGtB,mCAAE;QACD,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,MAAM;QACnB,KAAK,EAAE,IAAI;QAEX,sCAAE;UACD,OAAO,EAAE,YAAY;UACrB,MAAM,EAAE,IAAI;UAEf,UAAU,EAAE,GAAG;UACf,YAAY,EAAE,KAAK;UACnB,MAAM,EAAE,cAAc;UAEtB,wCAAC;YACA,eAAe,EAAE,IAAI;YACrB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,YAAY;YAErB,WAAW,EAAE,GAAG;UAGjB,2CAAI;YACH,YAAY,EAAE,KAAK;YAEnB,iDAAO;cACN,KAAK,EAAC,GAAG;UAIX,6CAAQ;YACP,aAAa,EAAE,cAAc;EAOlC,mBAAK;IACJ,WAAW,EArNA,KAAK;IAsNb,OAAO,EAAE,qBAAqB;IAC9B,UAAU,EAAE,OAAO;IAEnB,0BAAM;MACL,OAAO,EAAE,IAAI;IAGd,iCAAa;MACf,OAAO,EAAE,KAAK;IAGf,0BAAQ;MACP,WAAW,EAAC,CAAC", 4 | "sources": ["default.scss"], 5 | "names": [], 6 | "file": "default.css" 7 | } 8 | -------------------------------------------------------------------------------- /examples/themes/default.scss: -------------------------------------------------------------------------------- 1 | $sideWidth : 15rem; 2 | $headHeight : 6rem; 3 | $test : 5px; 4 | 5 | html,body{ 6 | height:100%; 7 | margin:0; 8 | padding:0; 9 | font-size: 16px !important; 10 | line-height: 1; 11 | background:#fafafa; 12 | font-family: "Hiragino Sans GB", "Microsoft YaHei", 13 | "WenQuanYi Micro Hei", sans-serif; 14 | 15 | } 16 | 17 | code{ 18 | padding: .2rem .4rem; 19 | font-size: 90%; 20 | color: #bd4147; 21 | background-color: #f7f7f9; 22 | border-radius: .25rem; 23 | line-height:1.5; 24 | } 25 | 26 | iframe{ 27 | width:100%; 28 | height:100%; 29 | } 30 | 31 | ul, ol {list-style: none;margin:0;padding: 0px;} 32 | 33 | //框架样式 34 | .impex-layout { 35 | height: 100%; 36 | width: 100%; 37 | display: block; 38 | overflow: hidden; 39 | 40 | header{ 41 | position: fixed; 42 | right: 0; 43 | left: 0; 44 | z-index: 9; 45 | font-size: 2rem; 46 | background-color: #000; 47 | color: #fff; 48 | padding: 1rem; 49 | } 50 | 51 | .sidebar { 52 | white-space: nowrap; 53 | width: $sideWidth; 54 | position: fixed; 55 | border-right: 1px solid #ddd; 56 | float: left; 57 | height: 100%; 58 | overflow: hidden; 59 | transition: all .2s; 60 | 61 | 62 | .scrollpane { 63 | width: 100%; 64 | height: calc(100% - #{$headHeight}); 65 | 66 | padding-top: $headHeight; 67 | padding-bottom: 0; 68 | overflow: hidden; 69 | position: relative; 70 | background-color: #eee; 71 | 72 | .menu-items{ 73 | margin-left: .5rem; 74 | li.active a{ 75 | background: #d2d7dc; 76 | color: #fff !important; 77 | } 78 | a{ 79 | color: #666 ; 80 | padding: .2rem 1rem; 81 | display: block; 82 | text-decoration: none; 83 | line-height: 1.5; 84 | 85 | &.cate{ 86 | outline: none; 87 | width: 80%; 88 | padding: .5rem 2rem .5rem 1rem; 89 | position: relative; 90 | display: inline-block; 91 | margin: .5rem 0; 92 | overflow: hidden; 93 | background: #718a90; 94 | color: #fff ; 95 | } 96 | 97 | &.link:hover{ 98 | background: #fafafa; 99 | text-decoration: underline; 100 | color: #666 !important; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | .sidebar.hidden{ 107 | width: 0; 108 | white-space: nowrap; 109 | overflow: hidden; 110 | border-right:none; 111 | } 112 | 113 | .togglebar { 114 | position: fixed; 115 | display: flex; 116 | flex-direction: row; 117 | top: 4rem; 118 | width: 100%; 119 | background-color: #ddd; 120 | z-index: 9; 121 | border:1px solid #ddd; 122 | border-width: 1px 0 1px 0; 123 | 124 | .menubar{ 125 | width: $sideWidth; 126 | position: relative; 127 | line-height: 1.5; 128 | transition: width .2s; 129 | 130 | .toggler{ 131 | position: absolute; 132 | right: .5rem; 133 | line-height: 1.6; 134 | border:1px solid transparent; 135 | padding: 0 .5rem; 136 | 137 | &:hover{ 138 | border:1px solid #ddd; 139 | } 140 | } 141 | } 142 | .menubar.hidden{ 143 | width: 2rem; 144 | white-space: nowrap; 145 | overflow: hidden; 146 | } 147 | 148 | .tabbar{ 149 | bottom: -1px; 150 | height: 85%; 151 | flex:1; 152 | overflow: hidden; 153 | position: relative; 154 | 155 | .nav{ 156 | padding: 5px .2rem; 157 | position: absolute; 158 | left: 0rem; 159 | margin-top: 1px; 160 | } 161 | .nav.right{ 162 | left:auto; 163 | right: 1rem; 164 | } 165 | .nav:hover{ 166 | border:1px solid #ddd; 167 | } 168 | 169 | .slidebox{ 170 | overflow: hidden; 171 | height: 100%; 172 | margin: 0 2rem 0 1rem; 173 | } 174 | 175 | ul{ 176 | margin: 0; 177 | height: 100%; 178 | white-space: nowrap; 179 | width: 100%; 180 | 181 | li{ 182 | display: inline-block; 183 | height: 100%; 184 | 185 | margin-top: 1px; 186 | margin-right: .5rem; 187 | border: 1px solid #ddd; 188 | 189 | a{ 190 | text-decoration: none; 191 | padding: 0 1rem; 192 | display: inline-block; 193 | 194 | line-height: 1.5; 195 | } 196 | 197 | i.fa{ 198 | margin-right: .5rem; 199 | 200 | &:hover{ 201 | color:red; 202 | } 203 | } 204 | 205 | &.active{ 206 | border-bottom: 1px solid #fff; 207 | } 208 | } 209 | } 210 | } 211 | } 212 | 213 | .main{ 214 | margin-left: $sideWidth; 215 | padding: 7.5rem 1rem 2rem 1rem; 216 | transition: all .3s; 217 | 218 | .panel{ 219 | display: none; 220 | } 221 | 222 | .panel.active{ 223 | display: block; 224 | } 225 | 226 | &.hidden{ 227 | margin-left:0; 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /ext/impex.ext.loadable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * loadable提供一个基于ajax的组件加载接口,可以简化组件加载写法 3 | * 4 | * 兼容性:IE 9+ 5 | */ 6 | !function(g){ 7 | /** 8 | * 加载指定url 9 | * @param {[type]} url [description] 10 | * @return {Function} 返回一个符合promise接口的回调函数 11 | */ 12 | g.loadable = function(url) { 13 | return function(resolve,reject) { 14 | ajax(url,resolve,reject); 15 | }; 16 | } 17 | 18 | function ajax(url,resolve,reject) { 19 | var xhr = new XMLHttpRequest(); 20 | xhr.open('get',url,true); 21 | xhr.onerror = reject; 22 | xhr.__resolve = resolve; 23 | if(xhr.onload === null){ 24 | xhr.onload = onload; 25 | }else{ 26 | xhr.onreadystatechange = onload; 27 | } 28 | xhr.url = url; 29 | xhr.send(null); 30 | } 31 | 32 | function onload(){ 33 | if(this.status===0 || //local 34 | ((this.status >= 200 && this.status <300) || this.status === 304) ){ 35 | var txt = this.responseText; 36 | this.__resolve(txt); 37 | } 38 | } 39 | 40 | }(window); 41 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | concat = require('gulp-concat'), 3 | uglify = require('gulp-uglify'), 4 | rename = require('gulp-rename'), 5 | header = require('gulp-header'), 6 | removeCode = require('gulp-remove-code'), 7 | del = require('del'), 8 | stripDebug = require('gulp-strip-debug'); 9 | 10 | 11 | var banner = [ 12 | '/*' 13 | ,' * impexjs is a powerful web application engine to build ' 14 | ,' * reactive webUI system' 15 | ,' *' 16 | ,' *' 17 | ,' * Copyright 2015-'+ new Date().getFullYear() +' MrSoya and other contributors' 18 | ,' * Released under the MIT license' 19 | ,' *' 20 | ,' * website: http://impexjs.org' 21 | ,' * last build: '+new Date().toLocaleDateString() 22 | ,' */' 23 | ].join('\n') + '\n'; 24 | 25 | var libs = [ 26 | 'src/shellStart.js', 27 | 'src/core/basic.js', 28 | 'src/core/util.js', 29 | 'src/core/parser.js', 30 | 'src/core/compiler.js', 31 | 32 | 'src/observe/Change.js', 33 | 'src/observe/Monitor.js', 34 | 'src/observe/observer.js', 35 | 36 | 'src/vdom/vnode.js', 37 | 'src/vdom/builder.js', 38 | 'src/vdom/transform.js', 39 | 'src/vdom/comparer.js', 40 | 41 | 'src/component/EventEmitter.js', 42 | 'src/component/Component.js', 43 | 'src/component/Task.js', 44 | 'src/component/watchers.js', 45 | 46 | 'src/impex.js', 47 | 48 | 'src/directive/build-in.js', 49 | 'src/filter/build-in.js', 50 | 51 | 'src/shellEnd.js' 52 | ]; 53 | 54 | gulp.task('build-dev', ['clean'], function() { 55 | return gulp.src(libs) 56 | .pipe(concat('impex.dev.all.js')) 57 | .pipe(header(banner)) 58 | .pipe(gulp.dest('build')) 59 | .pipe(gulp.dest('examples/lib/impex')) 60 | .pipe(rename({suffix: '.min'})) 61 | .pipe(uglify()) 62 | .pipe(header(banner)) 63 | .pipe(gulp.dest('build')); 64 | }); 65 | gulp.task('build-prod', ['clean'], function() { 66 | return gulp.src(libs) 67 | .pipe(concat('impex.prod.all.js')) 68 | .pipe(header(banner)) 69 | .pipe(removeCode({ production: true })) 70 | .pipe(stripDebug()) 71 | .pipe(gulp.dest('build')) 72 | .pipe(gulp.dest('examples/lib/impex')) 73 | .pipe(rename({suffix: '.min'})) 74 | .pipe(uglify()) 75 | .pipe(header(banner)) 76 | .pipe(gulp.dest('build')); 77 | }); 78 | 79 | gulp.task('clean', function(cb) { 80 | del(['build'], cb) 81 | }); 82 | 83 | gulp.task('default', ['build-dev','build-prod']); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "impex", 3 | "description": "a powerful web application engine", 4 | "version": "0.98.0", 5 | "nodejs": "6.11.2", 6 | "author": [ 7 | { 8 | "name": "MrSoya", 9 | "email": "kenyue@foxmail.com" 10 | } 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git@github.com:MrSoya/impex.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/MrSoya/impex/issues" 18 | }, 19 | "license": "MIT", 20 | "main": "gulpfile.js", 21 | "devDependencies": { 22 | "del": "~1.2.1", 23 | "gulp-strip-debug": "~3.0.0", 24 | "gulp": "^3.9.1", 25 | "gulp-concat": "~2.6.0", 26 | "gulp-header": "~1.8.7", 27 | "gulp-remove-code": "^3.0.2", 28 | "gulp-rename": "~1.2.0", 29 | "gulp-uglify": "~1.2.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/component/EventEmitter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @classdesc 事件类,为所有组件提供自定义事件接口 3 | * 4 | * @class 5 | */ 6 | function EventEmitter(){ 7 | this._eeMap = {}; 8 | } 9 | EventEmitter.prototype = { 10 | /** 11 | * 事件注册不支持队列。相同类型的事件注册会被覆盖 12 | * @param {String} type 事件类型 13 | * @param {Function} handler 回调函数 14 | * @param {Object} [context] 上下文 15 | * @return {Object} 返回事件函数返回值 16 | */ 17 | $on:function(type,handler,context) { 18 | this._eeMap[type] = [handler,context||this]; 19 | return this; 20 | }, 21 | /** 22 | * 取消事件注册 23 | * @param {[type]} type [description] 24 | * @return {[type]} [description] 25 | */ 26 | $off:function(type) { 27 | this._eeMap[type] = null; 28 | }, 29 | $emit:function(type){ 30 | var pair = this._eeMap[type]; 31 | if(!pair)return; 32 | var fn = pair[0], 33 | ctx = pair[1]; 34 | if(!fn)return; 35 | 36 | var args = []; 37 | for(var i=1;i0) 42 | lcQ.push(lcMap); 43 | }); 44 | ctor.lcq = lcQ; 45 | 46 | for(var k in fns){//组件优先 47 | if(!ctor.prototype[k]) 48 | ctor.prototype[k] = fns[k]; 49 | } 50 | } 51 | 52 | return ctor; 53 | } 54 | function isObject(obj){ 55 | return typeof(obj) === 'object' && obj !== null; 56 | } 57 | function isArray(obj){ 58 | return Array.isArray(obj); 59 | } 60 | function isString(obj){ 61 | return typeof obj === 'string'; 62 | } 63 | function isUndefined(obj){ 64 | return obj === undefined; 65 | } 66 | function isDefined(obj){ 67 | return obj !== undefined; 68 | } 69 | function isFunction(obj){ 70 | return obj instanceof Function; 71 | } 72 | -------------------------------------------------------------------------------- /src/core/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统常量 3 | * 包括所有语法标识符、错误信息等 4 | */ 5 | 6 | var CMD_PREFIX = 'x-';//指令前缀 7 | var CMD_PARAM_DELIMITER = ':'; 8 | var CMD_MODIFIER_DELIMITER = '.'; 9 | 10 | //modifiers 11 | var EVENT_MODIFIER_NATIVE = 'native'; 12 | var EVENT_MODIFIER_STOP = 'stop'; 13 | var EVENT_MODIFIER_PREVENT = 'prevent'; 14 | var EVENT_MODIFIER_SELF = 'self'; 15 | 16 | var EXP_START_TAG = '{{', 17 | EXP_END_TAG = '}}'; 18 | var REG_CMD = /^x-.*/; 19 | var ATTR_REF_TAG = 'ref'; 20 | var ATTR_ID_TAG = 'id'; 21 | var ATTR_SLOT_TAG = 'slot'; 22 | var COMP_SLOT_TAG = 'component'; 23 | var PROP_TYPE_PRIFX = '.'; 24 | 25 | var EVENT_AB_PRIFX = '@'; 26 | var BIND_AB_PRIFX = '.'; 27 | var EXP_EXP = new RegExp(EXP_START_TAG+'(.+?)(?:(?:(?:=>)|(?:=>))(.+?))?'+EXP_END_TAG,'img'); 28 | 29 | var DOM_COMP_ATTR = 'impex-component'; 30 | 31 | var im_counter = 0; 32 | 33 | var DISPATCHERS = []; 34 | var FILTER_MAP = {}; 35 | var DIRECT_MAP = {}; 36 | var COMP_MAP = {'component':1}; 37 | var EVENT_MAP = {}; 38 | var PLUGIN_LIST = []; 39 | var Mixins = [];//global mixins 40 | var TickMap = { 41 | g:[] 42 | }; 43 | 44 | var LC_DI = {//指令生命周期 45 | 'bind':'bind', 46 | 'appended':'appended', 47 | 'update':'update', 48 | 'unbind':'unbind' 49 | }; 50 | var LC_CO = {//指令生命周期 51 | 'created':'created', 52 | 'compile':'compile', 53 | 'willMount':'willMount', 54 | 'mounted':'mounted', 55 | 'destroy':'destroy', 56 | 'willUpdate':'willUpdate', 57 | 'updated':'updated', 58 | 'propsChange':'propsChange' 59 | }; 60 | 61 | //debugs 62 | var DebugMap = { 63 | attrs:{}, 64 | events:{}, 65 | directs:{}, 66 | txt:{}, 67 | filter:{} 68 | }; 69 | function setDebugMap(node,name,rowNum,colPos,len,type) { 70 | var map = DebugMap[type][node.rid]; 71 | if(!map){ 72 | map = DebugMap[type][node.rid] = {}; 73 | } 74 | map[name] = {r:rowNum,c:colPos,l:len}; 75 | } 76 | 77 | var PluginInited = false; 78 | 79 | //removeIf(production) 80 | function error(comp,desc,e,stack){ 81 | var msg = 'Impex error : ' 82 | +(desc||'') 83 | +(e?' - '+e.message:'') 84 | //+'\nFor more information about the xerror,please visit the following address: http://impexjs.org/doc/techniques.html#techniques-xerror' 85 | +'\n\n'; 86 | if(stack)msg += stack; 87 | var stackRowStr = '\n '; 88 | if(isString(comp)){ 89 | comp = impex._cs[comp]; 90 | } 91 | var target = comp?comp.$name:'ROOT'; 92 | msg += '\n---> <' + target +'>'; 93 | if(comp){ 94 | var p = comp.$parent; 95 | var indents = ' '; 96 | while(p){ 97 | msg += '\n'+indents+'<' + p.$name +'>'; 98 | p = p.$parent; 99 | indents += ' '; 100 | } 101 | } 102 | 103 | console.error(msg); 104 | } 105 | function assert(isTrue,comp,code,msg,e) { 106 | !isTrue && error(comp,msg,e); 107 | } 108 | function getStack(compId,rid,k,type) { 109 | var comp = impex._cs[compId]; 110 | var map = DebugMap[type][rid]; 111 | var debugInfo = map[k]; 112 | 113 | //生成调试信息 114 | var errorMsg = ''; 115 | var prveMsgs = []; 116 | var nextMsgs = []; 117 | var findError = false; 118 | for(var i=0;i1){ 124 | if(comp._tmplRows[i+1]){ 125 | nextMsgs.push('...\n'); 126 | } 127 | break; 128 | } 129 | continue; 130 | } 131 | 132 | prveMsgs.push(rowMsg); 133 | if(prveMsgs.length>2)prveMsgs.shift(); 134 | if(debugInfo.r == i){ 135 | var waveLine = ''; 136 | for(var s=0;s=debugInfo.c+debugInfo.l){ 140 | break; 141 | }else{ 142 | waveLine += '^'; 143 | } 144 | } 145 | var blanks = ''; 146 | for(var l=(i+'').length;l--;){ 147 | blanks += ' '; 148 | } 149 | errorMsg += blanks+waveLine+'\n'; 150 | 151 | findError = true; 152 | } 153 | } 154 | prveMsgs = prveMsgs.join(''); 155 | if(i>1)prveMsgs = '...\n'+prveMsgs; 156 | return prveMsgs+errorMsg+nextMsgs.join(''); 157 | } 158 | 159 | var XERROR = { 160 | COMPONENT:{//1XXX 161 | CONTAINER:1001, 162 | TEMPLATEPROP:1002, 163 | LOADERROR:1003, 164 | LOADTIMEOUT:1004, 165 | TEMPLATETAG:1005, 166 | COMPUTESTATE:1006, 167 | DEP:1007, 168 | STATE:1008, 169 | MIXINS:1009 170 | }, 171 | COMPILE:{//2XXX 172 | ONEROOT:2001, 173 | EACH:2002, 174 | HTML:2003, 175 | ROOTTAG:2004, 176 | ROOTCOMPONENT:2005, 177 | NOFILTER:2006, 178 | ERROR:2007 179 | }, 180 | //COMPONENT ATTRIBUTE ERRORS 181 | INPUT:{//3XXX 182 | REQUIRE:3001, 183 | TYPE:3002 184 | }, 185 | PLUGIN:{//4xxx 186 | NOINSTALL:4001 187 | } 188 | } 189 | //endRemoveIf(production) 190 | -------------------------------------------------------------------------------- /src/filter/build-in.js: -------------------------------------------------------------------------------- 1 | impex.filter('json',function(v){ 2 | return JSON.stringify(v); 3 | }) 4 | 5 | //filterBy:'xxx' 6 | //filterBy:'xxx':'name' 7 | //filterBy:filter 8 | .filter('filterBy',function(v,key,inName){ 9 | var ary = v; 10 | if(!isArray(ary)){ 11 | return v; 12 | } 13 | var rs = []; 14 | if(isFunction(key)){ 15 | for(var i=ary.length;i--;){ 16 | var need = key.call(this,ary[i]); 17 | if(need){ 18 | rs.unshift(ary[i]); 19 | } 20 | } 21 | }else{ 22 | for(var i=ary.length;i--;){ 23 | var item = ary[i]; 24 | if(inName){ 25 | if(!key || (item[inName]+'').indexOf(key) > -1){ 26 | rs.unshift(item); 27 | } 28 | }else{ 29 | if(!key || item.indexOf && item.indexOf(key) > -1){ 30 | rs.unshift(item); 31 | } 32 | } 33 | } 34 | } 35 | return rs; 36 | }) 37 | 38 | //[1,2,3,4,5] => limitBy:3:1 ----> [2,3,4] 39 | .filter('limitBy',function(v,count,start){ 40 | if(!isArray(v)){ 41 | return v; 42 | } 43 | v = v.concat(); 44 | if(!count)return v; 45 | return v.splice(start||0,count); 46 | }) 47 | 48 | //[1,2,3,4,5] => orderBy:'':'desc' ----> [5,4,3,2,1] 49 | .filter('orderBy',function(v,key,dir){ 50 | if(!key && !dir)return v; 51 | if(!isArray(v)){ 52 | return v; 53 | } 54 | v = v.concat(); 55 | v.sort(function(a,b){ 56 | var x = key?a[key]:a, 57 | y = key?b[key]:b; 58 | 59 | if(typeof x === "string"){ 60 | return x.localeCompare(y); 61 | }else if(typeof x === "number"){ 62 | return x - y; 63 | }else{ 64 | return (x+'').localeCompare(y); 65 | } 66 | }); 67 | if(dir === 'desc'){ 68 | v.reverse(); 69 | } 70 | return v; 71 | }); -------------------------------------------------------------------------------- /src/observe/Change.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 当属性发生变更时,一个变更对象会被创建并通过watcher传递给handler 3 | */ 4 | function Change(name,newVal,oldVal,object){ 5 | this.name = name; 6 | this.newVal = newVal; 7 | this.oldVal = oldVal; 8 | this.object = object; 9 | } -------------------------------------------------------------------------------- /src/observe/Monitor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 监控属性的变更以及依赖收集 3 | */ 4 | function Monitor(key,value,target,parent){ 5 | this.key = key; 6 | this.target = target; 7 | this.value = value; 8 | this.watchers = []; 9 | this.parent = parent; 10 | } 11 | Monitor.prototype = { 12 | /** 13 | * 通知watcher进行更新 14 | */ 15 | notify:function(newVal) { 16 | this.value = newVal; 17 | 18 | var c = new Change(this.key,newVal,this.value,this.target); 19 | this.watchers.forEach(function(watcher) { 20 | watcher(c); 21 | }); 22 | 23 | //通知父对象 24 | if(this.parent){ 25 | this.parent.notify(this.parent.value); 26 | } 27 | }, 28 | /** 29 | * 收集依赖 30 | */ 31 | collect:function() { 32 | var mt = Monitor.target; 33 | 34 | if(mt){ 35 | if(!mt.monitors){ 36 | mt.monitors = []; 37 | }//record to del 38 | if(mt.monitors.indexOf(this)<0){ 39 | mt.monitors.push(this); 40 | mt.key = this.key; 41 | } 42 | if(this.watchers.indexOf(mt)<0) 43 | this.watchers.push(mt); 44 | } 45 | }, 46 | /** 47 | * 删除已监控的watcher 48 | */ 49 | removeWatcher:function(watcher) { 50 | var i = this.watchers.indexOf(watcher); 51 | if(i>-1){ 52 | this.watchers.splice(i,1); 53 | } 54 | } 55 | }; -------------------------------------------------------------------------------- /src/shellEnd.js: -------------------------------------------------------------------------------- 1 | 2 | if ( typeof module === "object" && typeof module.exports === "object" ) { 3 | module.exports = impex; 4 | }else{ 5 | global.impex = impex; 6 | } 7 | 8 | }(window||this); -------------------------------------------------------------------------------- /src/shellStart.js: -------------------------------------------------------------------------------- 1 | !function (global) { 2 | 'use strict'; -------------------------------------------------------------------------------- /src/vdom/builder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * VDOM构建器,用来构建VDOM树 3 | */ 4 | function createElement(rootNode,comp,cls,style,attrs,directs,events,rid,children,html){ 5 | var raw = RNODE_MAP[rid]; 6 | var tag = raw.tag; 7 | if(tag == ATTR_SLOT_TAG)return; 8 | 9 | var rs = new VNode(tag,raw,attrs,directs,events,raw.ref,cls,style); 10 | 11 | var isComp = COMP_MAP[tag] || tag == 'component'; 12 | /** 13 | * 对组件顶级节点绑定组件原生事件和组件指令 14 | */ 15 | if(rootNode){ 16 | var cevs = comp._natives; 17 | if(cevs){ 18 | if(!rs.events)rs.events = {}; 19 | for(var k in cevs){ 20 | rs.events[k] = cevs[k]; 21 | } 22 | } 23 | var cdis = comp._directives; 24 | if(cdis){ 25 | if(!rs.directives)rs.directives = {}; 26 | for(var k in cdis){ 27 | rs.directives[k] = cdis[k]; 28 | } 29 | } 30 | } 31 | 32 | if (isComp) { 33 | rs._comp = true; 34 | rs._innerHTML = raw.innerHTML; 35 | 36 | return rs; 37 | } 38 | if(html != null){ 39 | children = html.children || []; 40 | } 41 | 42 | if(children.length>0){ 43 | rs.children = []; 44 | children.forEach(function(node){ 45 | if(node){ 46 | if(node instanceof Array){ 47 | node.forEach(function(c){ 48 | c.parent = rs; 49 | rs.children.push(c); 50 | }); 51 | }else{ 52 | node.parent = rs; 53 | rs.children.push(node); 54 | }//end if 55 | }//end if 56 | }); 57 | } 58 | 59 | return rs; 60 | } 61 | function createTemplate(children){ 62 | var rs = []; 63 | if(children.length>0){ 64 | children.forEach(function(node){ 65 | if(node){ 66 | if(node instanceof Array){ 67 | node.forEach(function(c){ 68 | rs.push(c); 69 | }); 70 | }else{ 71 | rs.push(node); 72 | }//end if 73 | }//end if 74 | }); 75 | } 76 | 77 | return rs; 78 | } 79 | function createText(txt){ 80 | var rs = new VNode(); 81 | rs.txt = txt && txt.toString?txt.toString():txt; 82 | return rs; 83 | } 84 | function createElementList(ds,iterator,scope){ 85 | var rs = []; 86 | ds.forEach(function(item,i){ 87 | var tmp = iterator.call(scope,i,item,i); 88 | if(tmp){ 89 | if(isArray(tmp)){ 90 | rs = rs.concat(tmp); 91 | }else{ 92 | rs.push(tmp); 93 | } 94 | } 95 | }); 96 | return rs; 97 | } 98 | function doFilter(v,filters,comp){ 99 | for(var i=0;i0){ 23 | for(var i=0;i') 41 | .replace(/ /img,'\u00a0') 42 | .replace(/&/img,'&'):str; 43 | } 44 | //创建有类型组件 45 | function newComponentOf(vnode,type,el,parent,props){ 46 | //handle component 47 | if(type == 'component'){ 48 | type = props.is; 49 | } 50 | var c = new COMP_MAP[type](props); 51 | c.$name = type; 52 | c.$el = el; 53 | c.$vel = vnode; 54 | c._directives = vnode.directives; 55 | var attrs = vnode.attrs; 56 | //bind parent 57 | parent._append(c); 58 | //ref 59 | if(vnode.ref){ 60 | parent.$ref[vnode.ref] = c; 61 | } 62 | //global 63 | if(attrs && attrs[ATTR_ID_TAG]){ 64 | impex.id[attrs[ATTR_ID_TAG]] = c; 65 | } 66 | 67 | c._innerHTML = vnode._innerHTML; 68 | 69 | return c; 70 | } -------------------------------------------------------------------------------- /src/vdom/vnode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 虚拟节点 3 | * 保存编译前和编译后的信息 4 | */ 5 | var vn_counter = 0; 6 | var rn_counter = 0; 7 | function RawNode(tag) { 8 | this.rid = rn_counter++; 9 | this.tag = tag; 10 | this.children; 11 | this.directives;//{name:{name,args,modifiers,exp,filters} 12 | this.attrs; 13 | this.txtQ; 14 | this.ref; 15 | this.events; 16 | this.class; 17 | this.style; 18 | this.isComp = false; 19 | this.outerHTML; 20 | this.innerHTML; 21 | } 22 | function VNode(tag,rawNode,attrs,di,events,ref,cls,style){ 23 | this.tag = tag; 24 | this.txt; 25 | this.children; 26 | this.dom; 27 | this.vid = vn_counter++; 28 | this.attrs = attrs; 29 | this.directives = di; 30 | this.events = events; 31 | this.ref = ref; 32 | this.class = cls; 33 | this.style = style; 34 | this.scope;//组件 35 | //原始信息 36 | this.raw = rawNode; 37 | } 38 | VNode.prototype = { 39 | /** 40 | * 绑定事件到该节点 41 | * @param {String} type 事件类型 42 | * @param {Function} handler 事件处理函数 43 | * @param {Array} modifiers 修饰符数组 44 | */ 45 | on:function(type,handler,modifiers){ 46 | var evMap = EVENT_MAP[type]; 47 | if(!evMap){ 48 | evMap = EVENT_MAP[type] = {}; 49 | } 50 | var vid = this.vid; 51 | function closure(e) { 52 | return EventFilter(vid,e); 53 | } 54 | evMap[this.vid] = [this,modifiers,handler,closure]; 55 | 56 | this.dom.addEventListener(type,closure,true); 57 | }, 58 | /** 59 | * 卸载事件 60 | * @param {String} [type] 事件类型。为空时,卸载所有事件 61 | */ 62 | off:function(type){ 63 | var evMap = EVENT_MAP[type]; 64 | if(evMap && evMap[this.vid]){ 65 | var fn = evMap[this.vid][3]; 66 | evMap[this.vid] = null; 67 | this.dom.removeEventListener(type,fn,true); 68 | }else if(!type){ 69 | for(var k in EVENT_MAP){ 70 | evMap = EVENT_MAP[k]; 71 | if(evMap && evMap[this.vid]){ 72 | var fn = evMap[this.vid][3]; 73 | evMap[this.vid] = null; 74 | this.dom.removeEventListener(k,fn,true); 75 | } 76 | } 77 | } 78 | 79 | } 80 | }; 81 | /** 82 | * 处理事件过滤,包括修饰符,返回值 83 | */ 84 | function EventFilter(vid,e) { 85 | var type = e.type; 86 | var evMap = EVENT_MAP[type]; 87 | if(!evMap)return; 88 | var tmp = evMap[vid]; 89 | if(!tmp)return; 90 | 91 | var vnode = tmp[0]; 92 | var t = e.target; 93 | 94 | //处理前置修饰符 95 | var modifiers = tmp[1]; 96 | if(modifiers && modifiers.length>0){ 97 | //键盘事件 98 | if(type.indexOf('key')===0){ 99 | var keys = modifiers.filter(function(mod) { 100 | switch(mod){ 101 | case EVENT_MODIFIER_NATIVE: 102 | case EVENT_MODIFIER_STOP: 103 | case EVENT_MODIFIER_PREVENT: 104 | case EVENT_MODIFIER_SELF: 105 | return false; 106 | } 107 | return true; 108 | }); 109 | 110 | if(keys[0] && e.key.toLowerCase() != keys[0])return; 111 | } 112 | if(modifiers.indexOf(EVENT_MODIFIER_SELF)>-1){ 113 | if(vnode.dom !== t)return; 114 | } 115 | } 116 | 117 | var fn = tmp[2]; 118 | var rs = fn.call(vnode.scope,e,vnode); 119 | 120 | //后置修饰符 121 | if(modifiers && modifiers.length>0){ 122 | if(modifiers.indexOf(EVENT_MODIFIER_STOP)>-1){ 123 | e.stopPropagation(); 124 | } 125 | if(modifiers.indexOf(EVENT_MODIFIER_PREVENT)>-1){ 126 | e.preventDefault(); 127 | } 128 | } 129 | 130 | return rs; 131 | } --------------------------------------------------------------------------------