大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

前端view指令

使用Python来写ajax交互

view指令

view指令

前端是当今技术界最不成熟、变化最快的领域,前端开发人员往往干着吃力不讨好的苦逼活。

易度前端UI框架基于Python构建,一个语言打通前后端,并实现技术的平滑过渡。

1   DOM操作

1.1   选择组件

选择器的使用,类似jquery,但是可以直接选择组件,包括:

  • tree
  • tabs

可以通过ID来直接定位对象:

view.select('tree#leftnav')

也可以通过klass来定位:

view.select('form.vertical')

找到当前事件触发节点最近的:

view.closest('tree')
view.closest('tabs').active_panel()

在区域内部查找:

view.closest('panel').find('tree')

1.2   标准Jquery功能

对选择之后的结果,可以做如下动作:

  • .val(value)
  • .empty()
  • .data()
  • .hide()
  • .focus()
  • .blur()
  • .remove()
  • .add_class(class_name)
  • .remove_class(class_name)
  • .toggle_class(class_name)
  • .attr(name, value)
  • .data(name, value)
  • .val(value)
  • .css(name, value)
  • .replace(value)
  • .append(value)
  • .prepend(value)
  • .after(value)
  • .before(value)

1.3   填充内容 set_content

选择到组件之后,就可以控制组件。不同的组件有不同的控制方法。

比如对于面板panel,替换body区域内容:

view.closest('panel').set_content(ui.h1('hello'))

对于标准的layout组件:

view.select('#panel-12').set_content(ui.h1('hello'))

对树 ui.tree、标签页 ui.tabs ,也有各自的接口,具体参看组件说明文档。

1.4   直接写js append_script

可以直接输出一段js,比如:

view.append_script('''
window.alert('hello'); ''')

1.5   浏览器控制台打印日志

在调试程序的时候,打印日志是必须的了:

view.log('xxxxx')

1.6   创建子view new_view / merge_view

默认情况下view是全局变量,会立刻输出,但是有时候

如果需要遮罩输出,需要先输出组件内容,再输出组件脚本:

print ...

# 创建一个独立的子view
sub_view = view.new_view()
print root.call_script('xxx.xx:xxx', context=context, view=sub_view, id='xxxx', *args, **kw)
print ...

# 先弹出遮罩
view.modal(printed)
# 再合并子view
view.merge_view(sub_view)

merge_view默认立刻输出,也可以滞后或提前输出,比如强制到最末尾输出:

view.merge_view(sub_view, position=1)

其中 position 表示输出位置:

  • 0: 默认值,立刻输出
  • 1:滞后到最后输出
  • -1:提前到最开始输出

1.7   添加水印

例如给表单添加水印:

view.select('#mytable').add_watermark(text='test\n\n\n123')

add_watermark可选参数:

  • text: 水印文本
  • size: 水印大小
  • font: 水印字体
  • color: 水印颜色
  • alpha: 水印透明度
  • rotation: 水印旋转度

2   网页模板

2.1   主区域

设置中间的主区域内容,可以:

view.layout.main().set_content(form)

2.2   顶部区域

清空内容区上方列:

view.layout.above().empty()

2.3   左右侧区域

设置右侧区域的内容,可以:

view.layout.right().set_content(form)

也可以在右侧区域,补充一个内容:

view.layout.right().append(form)
view.layout.right().prepend(form)

左右侧列都可以显示隐藏:

view.layout.hide_left()
view.layout.show_left()
view.layout.hide_right()
view.layout.show_right()

2.4   侧边区域

view.layout.side().set_content(ui.button('sss'))

2.5   导航条

模板的导航区域也刷新:

view.layout.refresh('main_nav')
view.layout.refresh('sub_nav')

2.6   置顶批量选择区域

选择文件、表单的时候,会出现一个横条:

view.batch_actions.set_content(ui.button('asdfas'))

可以关闭这个横条:

view.batch_actions.close()

将某个内容,加入到批量选择条:

view.batch_actions.add(obj)

2.7   皮肤操作

设置当前view使用的皮肤:

view.use_skin('zopen.test:test_skin')

2.8   view.load加载资源

可以用于加载css/js/handlerbars模板:

# 加载软件包内的资源
view.load(['xxx.xxx:js/slimbox2.js', 'xxx.ss:slimbox2.css'])

这些静态资源文件默认会依据软件包的版本,在浏览器进行缓存。

如果发生变化,只需要设置应用的版本,便可强制浏览器使用新版本的资源文件。

在js中使用 load(['xxx.xx:aaa.js']) 的时候,如果需要也分版本缓存,需要预先通知前端各个软件包的资源版本号:

view.update_resource_version('zopen.message', 'xxx.xxxx')

也可以用于加载内置和外部的资源:

# 加载内置的css、js
view.load(['slimbox2.js', 'slimbox2.css'])
# 加载之后运行脚本
view.load(["https://g.alicdn.com/ilw/ding/0.9.9/scripts/dingtalk.js"], scripts=""" ... """)

3   信息提示

在软件包里面, 创建一个python脚本,ui的操作通过 view 来实现

3.1   站点消息提示

操作成功的信息提示:

view.message(message)

不影响操作正常运行,但是需要警示用户:

view.message(message, 'warning', )

导致当前操作中断的错误提示:

view.message(message, 'error', )

可以指定停留时间(停留2秒):

view.message('sssss', delay=2000)

如果希望是临时飘窗显示:

view.message(message, 'float')

3.2   声音提示

可以配合声音提示:

view.sound('info')
view.sound('error')
view.sound('warn')
view.sound('solved')

5   网页调用

5.1   浏览器历史

如果希望当前页面支持浏览器后退:

view.history.push_state(request, title, url='') # url可选
view.history.back()
view.history.go(2)

如果当前页面,只是一个modal窗口,回退的时候,希望关闭这个窗口,可以:

view.history.push_state(request, title, url, data={"modal":True})

5.2   发起服务端局部刷新请求

主动发起服务端的请求:

view.call(context, request, 'xxxx.xxx:xxx', aaa=1, bb=2)

这里发起请求和ui组件 on('click', context, reqeust, 'xxx.xxx:xxx') 是一样的。

在服务端可以通过, request.is_from_view() 来区分是否是由view发起的局部刷新请求。

5.3   跳转

参数url是跳转到地址:

view.redirect(url)

有时候希望延时3秒再跳转:

view.redirect(url, delay=3)

6   网页临时存储

6.2   localstorage操作

设置一个参数:

view.storage.set('url', 'http://everydo.com')

读取并显示参数:

url = view.storage.get('url')

这个url是一个需要在前端运行才能得到的表达式,可以用作view指令的参数:

view.message(url)
view.redirect(url)

删除一个数据:

view.storage.remove('url')

7   远端view指令

可以通过消息频道,在指定用户的远端web发送前端指令。

7.1   得到远端view get_view

首先要通过用户的私有通讯频道,找到远端view:

messenger = root.get_messenger()
channel = messenger.get_private_channel(request.me.id)
remote_view = channel.get_view(context, request)

7.2   操作远端view

接下来,可以操作远端的view:

remote_view.message('hello')
remote_view.modal(ui.button('ok'))

可以看到,所有标准的view指令都可以支持的!

7.3   输出到远端 flush

最终将所有view指令发送到远端:

remote_view.flush()

8   vuejs混合开发

先用view.load(...) 加载vuejs组件:

view.load(['zopen.samples:component.js'])

view.component生成组件,可以绑定数据:

view.component('todo-item', id='test', props={'items': items})

props是一个dict,传递各个属性的值,每个值可以是 list,也可以是dict。

当属性发生变化的时候,会触发save事件:

view.component('todo-item', id='test', props={'items': items})
.on('save', context, reqeust, 'xxx.xxx:xxx')

也可以细化响应更具体的数据变化事件(??):

- list-append事件,数据为 {'prop_name':'items', data={}}
- list-insert事件,数据为 {'prop_name':'items', data={}}
- list-pop  {'prop_name':'items', data={}}
- list-update
- dict-del  {'prop_name':'items', data='key'}
- dict-update  {'prop_name':'items', data={key:value}}

也可以绑定事件:

view.component('button-counter')\
    .on('click', context, request, 'zopen.samples:ui_component', todo='clear')

通过view.model操作数据,自动更新绑定的UI

  1. 清除或者更改数据:

    view.model('todo-item#test').set('items', [])
    view.model('todo-item#test').set('items', [{'text':'set'}])
    
  2. 添加数据:

    view.model('todo-item#test')['items'].append({'text': todo})
    
  3. 批量添加数据:

    view.model('todo-item#test')['items'].extend([{'text': 'extend'}])
    
  4. 在指定位置添加数据:

    view.model('todo-item#test')['items'].insert(0, {'text': 'insert'})
    
  5. 在指定位置去除数据:

    # 在指定位置pop
    view.model('todo-item#test')['items'].pop(0)
    # 删除最后一个
    view.model('todo-item#test')['items'].pop()
    
  6. 修改某个数据:

    # 如果items是一个list类型
    view.model('todo-item#test')['items'].set(0, {'text':'set'})
    
    # 如果items是一个dict类型
    view.model('todo-item#test')['items'].set('aaa', {'text':'set'})