npm i -g @ttkjs/cli
依赖项:
- npm
- yarn
npm i -g yarn
ttkjs app helloworld
cd helloworld
yarn start
创建一个名叫helloworld的应用,并且运行起来
const state = {
data: {
content: 'hello ',
input: ''
}
}
- state很简单,可以理解为是应用的数据部分
- 引擎内部状态的存储结构是immutable类型
- 每次状态变化会通知view,重新render
@actionMixin('base')
class action {
constructor(option) {
Object.assign(this, option.mixins)
}
onChange = (e) => {
this.base.setState({ 'data.input': e.target.value })
console.log(this.base.getState('data.input'))
}
}
- action很简单,可以理解为是一些提供给ui调用的函数
- actionMixin,混入外部action,默认混入了ttkjs引擎base
- 详细参见后面高级概念
const view = {
component: 'div',
className: 'hello',
children: [{
component: 'div',
children: '{{data.content + data.input}}'
}, {
component: 'input',
placeholder: 'world',
value: '{{data.input}}',
onChange: '{{$onChange}}'
}]
}
- view很简单,可以理解为react的json化表示
- component是react组件名
- 详细参见后面高级概念
view的所有属性值支持表达式语法
表达式可以支持js语法,见下面示例
- 绑定state中path为data.content的数据
{
...
value: `{{data.content}}` //value = state.data.content
...
}
- 绑定action中方法名为onChange的函数
{
...
onChange:`{{$onChange}}` // onChange = action.$onChange
...
}
- 函数体
{
onChange: `{{{
debugger;
return $onChange
}}}`
/*
onChange = new Function(`
debugger;
return action.onChange
`)()
*/
}
{
component: 'div',
children: 'hello',
_visible: 'true'
}
这里说的系统属性就是上面例子中的component、children、_visible等; 除系统属性外还可以设置控件支持的任何属性; 主要支持下面描述的几种系统属性;
- component 组件名,缺省可使用所有html元素
{ component: 'div' } //<div></div>
- children 子组件
{
component: 'div'
children: {
component: 'div',
children: 'children'
}
}
/*
<div>
<div>chidlren</div>
</div>
*/
- _visible 是否显示,值支持表达式, 默认true
{
component: 'div',
_visible: false
}
_visible设置为false,将不创建该组件
- _for 循环,支持for嵌套
const state = {
data: {
list: [{a:1}, {a:2}, {a:3}]
}
}
const view = {
component: 'div',
children: {
_for: 'item in data.list', // or (item,index) in data.list
component: 'div',
children: '{{item.a}}'
}
}
- _function 函数,当组件的某个属性要求是一个函数并返回react 元素时使用它
import {registerComponent} from 'ttkjs'
class CustomComponent extends React.PureComponent {
render(){
var {getSub} = this.props
return (
<div>
{getSub('aaa','bbb')}
</div>
)
}
}
registerComponent('CustomComponent', CustomComponent)
const view = {
component: 'div',
children: {
component: 'CustomComponet'
getSub: {
_function: '(a,b)',
component: 'div',
children: '{{a+b}}'
}
}
}
view可以使用自定义组件或者外部的react组件,见下面示例
import React from 'react'
import { registerComponent } from 'ttkjs'
import { Button } from 'antd'
class CustomComponent extends React.PureComponent {
render() {
return (<div>custom component</div>)
}
}
registerComponent('CustomComponent', CustomComponent)
registerComponent('antd.Button', Button)
const view = {
component: 'div',
children: [{
component: 'CustomComponent'
},{
component: 'antd.Button',
children: 'Button'
}]
}
模板组件是为了减少view json的代码量提出的概念,把相似度很高、并且经常使用的一些json定义为模板组件,在使用中能有效减少代码量,见下面示例
import { registerTemplate } from 'ttkjs'
const CustomTemplate = function(props) {
return {
component: 'div',
children: [{
component: 'div',
children: props.content
},{
component: 'div',
children: props.content
}
]
}
}
registerTemplate( 'CustomTemplate', customTemplate)
const view = {
component: 'CustomTemplate',
content: 'hello'
}
ActionMixin提供了低耦合方式混入外部行为的可能,缺省并至少需要混入了ttkjs框架的base行为
- ttkjs引擎混入的base提供了哪些可用行为?
方法名 | 描述 | action中使用示例 | view中使用示例 |
---|---|---|---|
getState | 获取状态 | this.base.getState('data.input') | $base.getState('data.input') |
setState | 设置状态 | this.base.setState({'data.input', 'hello'}) | $base.setState({'data.input', 'hello'}) |
gs | =getState | this.base.gs('data.input') | $base.gs('data.input') |
ss | =setState | this.base.ss({'data.input', 'hello'}) | $base.ss({'data.input', 'hello'}) |
context | 上下文,支持get、set方法 | this.base.context.get('currentUser') or this.base.context.set('currentUser', {name: 'zhang'}) | $base.context.get('currentUser') |
- 如何混入自定义的行为类?
import { actionMixin, registerAction } from 'ttkjs'
class CustomAction {
alert = () => {
alert()
}
}
registerAction('CustomAction', CustomAction)
@actionMixin('base', 'CustomAction')
class action {
constructor(option) {
Object.assign(this, option.mixins)
}
}
const view = {
component: 'div',
onClick: '{{$CustomAction.alert}}'
}
把一个大型网站拆分成许多开发模式相同的app,这些app又可以独立运行、调试、分享,通过弱耦合的方式又能组合在一起成为一个网站
-
app来源
- ttkjs add 命令增加依赖, 会从hub.ttkjs.org下载依赖,类似yarn add
- package.json中subAppDir属性指向的目录,目录中如果存在应用代码会被扫描到
- 手动拷贝app.js 和 app.css到发布目录
-
组合使用
const view = {
component: 'div',
className: 'hello',
children: [{
component: 'AppLoader',
appName: 'app-test', //app name
content: 'hello' //app支持的属性
}]
}
- 手工创建
import {createAppElement} from 'ttkjs'
...
var ele = createAppElement('appName', {content: 'hello'}) //第一个参数:app name,第二参数:app props
...
- 预加载 修改index.html
ttkjs.load(['appName1', 'appName2']).then(()=>{
...
}
- navigate切换
import {navigate} from 'ttkjs'
navigate.redirect('/appName/')
- ttkjs提供hub.ttkjs.org网站用于分享开发者开发的应用
- 您可以通过ttkjs publish分享您的应用,publish前请使用 ttkjs build 、ttkjs build --dev 、ttkjs pkg 构建应用资源
import {registerComponent, registerAction} from 'ttkjs'
如上registerComponent,reigsterAction是两个api,所有支持的api如下
api | 参数 | 描述 |
---|---|---|
registerComponent | (key, component) | 注册组件 |
registerAction | (key, action) | 注册行为 |
registerTemplate | (key, template) | 注册模板 |
getComponent | (key) | 通过组件名获取组件 |
load | [应用名...] | 加载应用 |
createAppElement | (appName, appProps) | 创建app React Element |
setHoc | (hoc) | 设置最外层高阶React Element |
fetch | 对象类型,不需要参数 | 提供fetch对象,可以调用后台接口,或者mock |
navigate | 对象类型,不需要参数 | 提供navigate对象 |
render | (appName, targetHtmlElementName) | render |
可以使用ttkjs引擎提供fetch对象实现ajax,示例如下
action.js
import {fetch} from 'ttkjs'
...
fetch.post('/v1/login',{user: 'admin', password: '123'})
...
index.html, 配置fetch对象
window.main = function (ttkjs) {
ttkjs.utils.fetch.config({
mock: false, //默认是true
token: '',
after: function (response, url) {
return response
}
})
}
package.json,配置本地调试的webpack dev server proxy
...
"server": {
"proxy": {
"/v1/*": {
"target": "http://www.***.com:8080/"
}
},
"port": 8000
}
...
可以使用ttkjs引擎提供fetch对象实现mock,示例如下
action.js
import {fetch} from 'ttkjs'
...
fetch.post('/v1/login',{user: 'admin', password: '123'})
...
mock.js
import { fetch } from 'ttkjs'
const mockData = fetch.mockData
function initMockData() {
if (!mockData.users) {
mockData.users = [{
id: 1,
account: 13333333333,
password: 'c4ca4238a0b923820dcc509a6f75849b',
name: 'ttk'
}]
}
}
fetch.mock('/v1/login', (option, headers) => {
initMockData()
const user = mockData.users.find(o => o.account == option.account && o.password == option.password)
if (user) {
return {
result: true,
token: `${user.id},${user.account},${user.password},${user.name ? user.name : ''}`,
value: option
}
}
else {
return { result: false, error: { message: '请输入正确的用户名密码(系统内置用户user:13333333333,pwd:1)' } }
}
})
index.js
import 'mock.js'
index.html
window.main = function (ttkjs) {
ttkjs.utils.fetch.config({
mock: true
})
}
import {navigate} from 'ttkjs'
navigate.redirect('/portal') //https://www.***.com/#/portal
import {navigate} from 'ttkjs'
...
navigate.redirect('/sign-in') //https://www.***.com/#/sign-in
...
navigate.redirect('/portal') //https://www.***.com/#/portal
...
navigate.goBack() //https://www.***.com/#/sign-in
navigate.listen((location.action)=>{
debugger
//自定义处理
})
ttkjs cli 支持的所有命令如下
- ttkjs app
ttkjs app test
创建一个名为test应用
- ttkjs start
ttkjs start
ttkjs start --dev //dev模式启动
启动app,可以通过浏览器访问应用的运行结果,http://127.0.0.1:8000
- ttkjs build
ttkjs build
ttkjs build --dev //dev模式编译
编译应用,会在当前目录build目录下生成编译结果
- ttkjs pkg
ttkjs pkg
ttkjs pkg --dev //dev模式打包
- 感谢您对ttkjs的关注!