§ Fox2.0 前端框架(MPA)
§ 1 介绍
Fox多页面前端框架,主要是应用在Fox混合开发外壳和小程序、公众号上。
§ 2 工程结构
下面将会展示Fox前端框架的整体、前端和后端(可选)的结构,让大家有一个整体的认识。
§ 2.1 整体工程结构

如上图所示,工程主要分为前端页面和后端服务目录。前端页面目录主要是放置HTML、CSS、JS和相关的图片等用于web展示的资源文件。而后端服务主要是放置后台渠道访问服务、访问数据库服务等。
§ 2.2 前端工程结构

上图展示的目录结构如下
- custom目录:放置项目专属的js库、自定义组件等
- pages目录:放置web page,每个page由html/css/js文件组成
- libs目录:放置公共js库、组件库等
- theme目录:放置主题css/font、图片等
§ 2.3 后端工程结构(可选)

上图展示的目录结构如下
- filter目录:过滤器,用于截访问服务的请求,例如报文解析、权限检验、输入数据校验等
- example目录:示例的服务目录,service用于服务逻辑处理
- 配置文件目录:服务配置,用于定义服务的访问路径
§ 3 前端开发指南
本节主要介绍Fox前端开发的入门基础
§ 3.1 页面开发
Fox前端框架中最小的单位为page,每个page由html/css/js三个文件组成。可参考例子工程中pages/templates目录。如下
html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=yes,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="title" content="FOX">
<meta name="description" content="fox">
<meta name="keywords" content="fox">
<style>
html,body{
width:100%;
overflow: auto;
background-color:white;
}
</style>
<!----------- 基础库 start ------------->
<script type="text/javascript" src="../../libs/fox/fox-v1.2.5.js"></script>
<script type="text/javascript" src="../../libs/lib/libs-v1.0.0.js"></script>
<script type="text/javascript" src="../../libs/fox-ui/fox-ui-v1.0.0.js"></script>
<script type="text/javascript" src="../../libs/plugins/fox-plugins-v1.0.0.js"></script>
<script type="text/javascript" src="../../libs/templates/silk-v1.0.0.js"></script>
<script type="text/javascript" src="../../custom/main.js"></script>
<!----------- 基础库 end ---------------->
<!----------- 自定义库 start ------------>
<script type="text/javascript" src="../../custom/js/app.js"></script>
<link rel="stylesheet" href="../../custom/css/app.css" type="text/css" />
<link rel="stylesheet" href="../../themes/phone/css/iconfont.css" type="text/css" />
<!----------- 自定义库 end --------------->
<!----------- 导入页面css start ---------->
<!---在这里添加本页面的css--->
<link rel="stylesheet" href="templates.css" type="text/css" />
<!------------导入页面css end ------------>
</head>
<body>
<!---ID必须和vm中的el一致--->
<fox-page id="_my_page">
<!--header-->
<fox-header>
<!-- TODO 请重写此Header内容 START -->
<h1 class="fox-title">模版</h1>
<!-- TODO 请重写此Header内容 END -->
</fox-header>
<!--header-->
<fox-footer>
<!-- TODO 请重写此Footer内容 START -->
<h1>footer</h1>
<!-- TODO 请重写此Footer内容 END -->
</fox-footer>
<!--content-->
<fox-content class="my-flex-content">
<!-- TODO 请重写此部分内容 START -->
<h1>这是空白模板</h1>
<h1>这是空白模板</h1>
<!-- TODO 请重写此部分内容 END -->
</fox-content>
</fox-page>
</body>
<!----------- 导入页面js start --------------->
<!---在这里添加本页面的js--->
<script type="text/javascript" src="templates.js"></script>
<!------------导入页面js end ----------------->
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
JS
/**
* @created by {{username}} on {{sys_date}}
* @updated by
* @description {{pageDesc}}
*/
//vue data 在这里添加model数据
let vmData={}
//创建vue model
let vm=new Vue({
el:"#_my_page",
//数据
data:vmData,
//方法
methods:{},
//加载后处理
mounted:function(){},
//销毁前
beforeDestroy:function () {}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CSS
/**
* @created by {{username}} on {{sys_date}}
* @updated by
* @description {{pageDesc}}
*/
.blank {}
2
3
4
5
6
每个html都有对应的css/js,css和js必须在html上引用
§ 3.2 自定义组件开发
每个项目都有自己特殊的需求,这是无法在公共组件中提供的,所以我们也提供了自定义组件的扩展机制。自定义组件在custom/templates/my/components.js文件中扩展,建议每个自定义组件的前缀为“my-”,如my-button,my-text等
widget:
/**
* Created by jiangcheng on 2017/10/2.
*/
/**
* hello
*/
(function(vue, $, name) {
//注册组件
Vue.component(name, {
//模板
template: '\
<label>{{text}}</label>\
',
data:{
text:"hello world!"
}
})
})(Vue, $, "my-hello");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
§ 3.3 主题扩展
theme目录下面用于主题扩展,每个项目对css样式都由特殊需求,可以通过css进行重新定制。
§ 4 后端开发指南(可选)
这节将会展示如何开发service和过滤器,当然由于前端框架是前后端分离的,所以没规定必须使用fox server作为项目的后端应用服务。
§ 4.1 服务开发
每个服务由两部分组成:java文件和xml配置文件。java文件用于逻辑处理,而xml文件用于配置服务的访问路径和该服务的过滤器。如下
§ 4.1.1 普通服务开发
java
package service.example;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import service.common.bean.JsonRequest;
import service.common.bean.JsonResponse;
import cn.com.bankit.phoenix.resource.ResourceManager;
import cn.com.bankit.phoenix.session.Session;
import cn.com.bankit.phoenix.session.SessionManager;
import cn.com.bankit.phoenix.trade.Service;
/**
* demo service
*
* @author 江成
*
*/
public class DemoService extends Service<JsonRequest, JsonResponse> {
/**
* 构造函数
*/
public DemoService() {
super();
}
/**
* execute
*/
public JsonResponse execute(JsonRequest request) throws Exception {
String s=request.getData().toJSONString();
System.out.println("收到数据:"+s);
//定义返回数据
JsonResponse response=new JsonResponse();
//获取名称
String name=(String)request.get("name");
if("江成".equals(name)){
response.put("rp", "100 (哇,人品爆棚了good!!!)");
}else{
int rp=name.hashCode()%100;
StringBuilder sb=new StringBuilder();
sb.append(rp);
if(rp>=80){
sb.append(" (人品不错哦)");
}else if(rp>=60){
sb.append(" (人品一般般嘛)");
}else if(rp>30){
sb.append(" (人品真差)");
}else{
sb.append(" (人品那么差,兄弟你从前世就开始做坏事了)");
}
response.put("rp", sb.toString());
}
response.put("time", System.currentTimeMillis());
//response.put("test", getData());
System.out.println("返回数据:"+response.getData().toJSONString());
return response;
}
/**
* execute
*/
public JsonResponse login(JsonRequest request) throws Exception {
//-------------------------------------------------
//登陆成功后获取session,如果之前没有session会创建一个新的session
Session session = SessionManager.getInstance()
.getSessionFromCurrentThread(true);
//设置session登录状态为TRUE
session.login(true);
//定义返回数据
JsonResponse response=new JsonResponse();
response.put("rsp","success");
return response;
}
/**
* 获取测试数据
* @return
* @throws Exception
*/
@SuppressWarnings("unused")
private String getData() throws Exception{
ResourceManager resourceManager=ResourceManager.getInstance();
String workspaceRoot=resourceManager.getWorkspaceRoot();
String projectName=resourceManager.getProjectName(this.getClass());
String path=workspaceRoot+"/"+projectName+"/resource/para/dataSource/test.txt";
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
InputStream in = new BufferedInputStream(new FileInputStream(new File(path)));
try{
int len=-1;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))!=-1){
byteOut.write(buffer,0,len);
}
}finally{
in.close();
}
return byteOut.toString();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
服务一般继承Servie或BaseService,逻辑方法中入参为JsonRequest,出参为JsonResponse。当然对于非json格式交互数据的情况,如文件上传、文件下载服务,则需要使用HttpMessage作为入参和出参了
配置文件
<!--继承的名字是文件名,继承的文件必须为abstract为true的文件-->
<package name="demo" namespace="demo" extends="filter-auth.xml,filter-base.xml,filter-verify.xml">
<!-- demo测试 -->
<service name="demoService" class="service.example.DemoService"
method="execute">
<property name="verify" type="map">
<item key="name">require</item>
</property>
</service>
<!-- web socket测试 -->
<service name="webSocket" class="service.example.WebSocketService"
method="execute">
</service>
</package>
2
3
4
5
6
7
8
9
10
11
12
13
14
上面配置文件中定义了服务的访问路径、过滤器链路和对应的服务实现文件和方法。访问路径有三部分组成:package-name/namespace/name,如上面的访问路径如下 demo/demo/demoService。访问该服务需要通过filter-auth.xml,filter-base.xml,filter-verify.xml三个配置文件中定义的过滤器,而该服务对应的实现类为service.example.DemoService,而对应方法为execute。
§ 4.1.2 文件上传服务开发
java
package service.example;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import cn.com.bankit.phoenix.communication.http.FileItem;
import cn.com.bankit.phoenix.communication.http.HttpMessage;
import cn.com.bankit.phoenix.resource.ResourceManager;
import cn.com.bankit.phoenix.trade.Service;
/**
* 文件上传服务
*
* @author 江成
*
*/
public class UploadService extends Service<HttpMessage,HttpMessage>{
/**
* 执行
*/
@SuppressWarnings("unchecked")
public HttpMessage uploadFile(HttpMessage request) throws Exception {
System.out.println("-------------------> start");
Map<String,Object> map=(Map<String,Object>)request.getContent();
//文件item
List<FileItem> fileItems = new ArrayList<FileItem>();
//路径
String path = null;
for(String key:map.keySet()){
//获取item
Object item=map.get(key);
if(item instanceof FileItem){
System.out.println("0----> fileItem");
fileItems.add((FileItem)item);
}else if(item instanceof String[]){
String name=key;
Object value=map.get(name);
System.out.println("1----> name:"+name+" ,values:"+Arrays.toString((String[])value));
}else{
String name=key;
Object value=map.get(name);
System.out.println("2----> name:"+name+" ,value:"+value);
if("path".equals(key)){
path=(String)value;
}
}
}
for(int i=0,size=fileItems.size();i<size;i++){
FileItem fileItem=fileItems.get(i);
InputStream in=null;
OutputStream out =null;
String fileName = (String)map.get(("fileName-"+i));
try{
in=fileItem.getInputStream();
ResourceManager resMg=ResourceManager.getInstance();
String installRoot=resMg.getInstallRoot();
StringBuilder sb=new StringBuilder();
sb.append(installRoot);
sb.append("/");
sb.append(path);
sb.append("/");
sb.append(fileName);
System.out.println("------------>写入文件路径 path="+sb.toString());
File file=new File(sb.toString());
File parent = file.getParentFile();
if(!parent.isDirectory()){
parent.mkdirs();
}
//写入数据
out=new BufferedOutputStream(new FileOutputStream(file));
int len=-1;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))!=-1){
out.write(buffer,0,len);
}
out.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
if(in!=null){
try{
in.close();
}catch(Exception e){
//do nothing
}
}
if(out!=null){
try{
out.close();
}catch(IOException e){
//do nothing
}
}
}
}
System.out.println("-------------------> end");
HttpMessage response=new HttpMessage();
response.setContent("上传成功");
return response;
}
/**
* 上传大文件
*/
@SuppressWarnings("unchecked")
public HttpMessage uploadBigFile(HttpMessage request) throws Exception {
System.out.println("-------------------> start big");
Map<String,Object> map=(Map<String,Object>)request.getContent();
//记录文件名
String fileName=(String)map.get("fileName");
//记录片段开始位置
long start=Long.parseLong(map.get("start").toString());
//当前索引
int index=Integer.parseInt(map.get("index").toString());
//切片数量
int count=Integer.parseInt(map.get("count").toString());
//获取片段数据
FileItem fileItem=(FileItem)map.get("data");
//定义byte数据流
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
//定义输入流
InputStream in=null;
try{
//获取输入流
in=fileItem.getInputStream();
if(in==null){
HttpMessage response=new HttpMessage();
response.setContent("上传数据无效");
return response;
}
int len=0;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))!=-1){
byteOut.write(buffer, 0, len);
}
}finally{
if(in!=null){
//关闭输入流
try{
in.close();
}catch(Exception e){
//do nothing
}
}
}
//获取文件路径
ResourceManager resMg=ResourceManager.getInstance();
String installRoot=resMg.getInstallRoot();
StringBuilder sb=new StringBuilder();
sb.append(installRoot);
sb.append("/upload/");
sb.append(fileName);
String filePath=sb.toString();
//定义临时文件名
String tmpFilePath=filePath+".tmp";
File tempFile = new File(tmpFilePath);
File parent = tempFile.getParentFile();
if(!parent.isDirectory()){
parent.mkdirs();
}
//定义文件访问器
RandomAccessFile randomFile=null;
try{
//创建文件访问器
randomFile=new RandomAccessFile(tmpFilePath, "rw");
randomFile.seek(start);
randomFile.write(byteOut.toByteArray());
}finally{
//关闭文件访问器
if(randomFile!=null){
try{
randomFile.close();
}catch(Exception e){
//do nothing
}
}
}
//传输完成,修改为正常的文件名称
if(index==count){
File file=new File(tmpFilePath);
file.renameTo(new File(filePath));
System.out.println("写入文件:"+filePath);
}
System.out.println("写入片段 fileName:"+fileName+", index:"+map.get("index")+", count:"+map.get("count")+", start:"+start+", end:"+map.get("end"));
HttpMessage response=new HttpMessage();
response.setContent("上传成功");
System.out.println("-------------------> end big");
return response;
}
@Override
public HttpMessage execute(HttpMessage arg0) throws Exception {
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
配置文件
<!--继承的名字是文件名,继承的文件必须为abstract为true的文件-->
<package name="demo" namespace="file" extends="filter-auth.xml">
<!--直接文件上传 -->
<service name="upload" class="service.example.UploadService"
method="uploadFile">
</service>
<!--直接文件上传 -->
<service name="uploadBig" class="service.example.UploadService"
method="uploadBigFile">
</service>
<!--直接文件下载 -->
<service name="download" class="service.example.DownloadService"
method="downloadFile">
</service>
</package>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面文件上传服务中,由于数据为流,所以必须使用HttpMessage作为参数
§ 4.1.3 文件下载服务开发
java
package service.example;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;
import cn.com.bankit.phoenix.communication.http.HttpMessage;
import cn.com.bankit.phoenix.resource.ResourceManager;
/**
* 下载服务
* @author 江成
*
*/
public class DownloadService {
/**
* 构造函数
*/
public DownloadService() {
super();
}
/**
* 执行
*/
public HttpMessage downloadFile(HttpMessage httpMessage) throws Exception {
// 获取请求参数
@SuppressWarnings("unchecked")
Map<String, Object> reqMap = (Map<String, Object>) httpMessage
.getContent();
String path = (String) reqMap.get("path");
ResourceManager resMg=ResourceManager.getInstance();
String installRoot=resMg.getInstallRoot();
StringBuilder sb=new StringBuilder();
sb.append(installRoot);
sb.append("/");
sb.append(path);
System.out.println("------------>读取文件路径 path="+sb.toString());
File file=new File(sb.toString());
InputStream in = new BufferedInputStream(new FileInputStream(file));
HttpMessage respMsg = new HttpMessage();
respMsg.setHeader("Content-Type", "application/octet-stream");
respMsg.setContent(in);
return respMsg;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
配置文件
<!--继承的名字是文件名,继承的文件必须为abstract为true的文件-->
<package name="demo" namespace="file" extends="filter-auth.xml">
<!--直接文件上传 -->
<service name="upload" class="service.example.UploadService"
method="uploadFile">
</service>
<!--直接文件上传 -->
<service name="uploadBig" class="service.example.UploadService"
method="uploadBigFile">
</service>
<!--直接文件下载 -->
<service name="download" class="service.example.DownloadService"
method="downloadFile">
</service>
</package>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面文件下载服务中,由于数据为流,所以必须使用HttpMessage作为参数
§ 4.2 过滤器开发
过滤器同样由java和配置文件两部分组成,下面就用一个权限过滤器为例子,给大家展示过滤器如何开发。
java
package service.common.filter;
import both.common.util.LoggerUtil;
import cn.com.bankit.phoenix.communication.http.HttpMessage;
import cn.com.bankit.phoenix.session.Session;
import cn.com.bankit.phoenix.session.SessionManager;
import cn.com.bankit.phoenix.trade.filter.Event;
import cn.com.bankit.phoenix.trade.filter.Filter;
/**
* 消息解析过滤器
*
* @author 江成
*
*/
public class AuthFilter extends Filter {
/**
* 构造函数
*/
public AuthFilter() {
super();
}
/**
* before
*/
public void before(Event e) throws Exception {
//获取session manager
SessionManager sessionManager = SessionManager.getInstance();
//获取session
Session session = sessionManager.getSessionFromCurrentThread(false);
//由于是集群部署,session不可能在每台服务器都存在,所以如果内存中
//session不存在,那旧必须在HTTP message中获取sessionId,去数据库
//中校验,并还原
if(session == null){
// 获取入参
Object inBean = e.getInBean();
if (inBean instanceof HttpMessage) {
HttpMessage httpSession = (HttpMessage)inBean;
String id = httpSession.getHeader("sessionId");
if(id!=null){
//------读取数据库的登陆信息,检查session是否有效--------
//检查代码写在这里
//------------------------------------------------------
//使用指定的ID创建session
session = sessionManager.getSession(id, true);
//绑定session到当前线程
sessionManager.bindSessionToCurrentThread(session);
//设置session的登陆状态
session.login(true);
//-------还原session信息----------
session.setData("admin", "江成");
//-------------------------------
}else{
LoggerUtil.error("无法校验session-1");
// 抛出异常
throw new Exception("unlogin");
}
}else{
LoggerUtil.error("无法校验session-2");
// 抛出异常
throw new Exception("unlogin");
}
}else{
// 获取登录状态
Boolean loginStatus = session.isLogin();
if (!Boolean.TRUE.equals(loginStatus)) {
LoggerUtil.error("用户尚未登录");
// 抛出异常
throw new Exception("unlogin");
}
}
}
/**
* after
*/
public void after(Event e) throws Exception {
// do nothing
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
配置文件
<package name="filter-auth" abstract="true">
<!-- 权限 filter -->
<filter name="AuthFilter" class="service.common.filter.AuthFilter" scope="singleton">
</filter>
</package>
2
3
4
5
§ 5 多页面(MPA)支持
本节将会展示对MPA应用的支持,典型MPA的APP应用如下图

§ 5.1页面切换
在应用中除了通过点击或手势进行页面切换外,我们还需要通过代码调用的方式进行切换,代码如下:
//切换到页面2
fox.navigator.command("main_fragment","switch",2);
- 参数1:tab主框架名称
- 参数2:切换命令
- 参数3:切换页面索引
§ 5.2页面切换事件
tab切换到对应的view的时候,主框架会给对应子页面发送消息,接收函数如下
//注册消息服务tab selected
fox.navigator.registerMessageService("_fox_tab_selected",(type,data)=>{
console.info("select index:"+data);
});
2
3
4
- 参数1:消息类型,固定为_fox_tab_selected
- 参数2:消息处理函数
§ 5.3页面间消息发送
同样,tab页之间的消息也是通过command命令来实现的 发送方
//发消息给页面2
let msgData={
index:2,//页面索引
eventType:"custom_message", //消息类型
data:"我是谁?我在哪?" //消息内容
}
fox.navigator.command("main_fragment","sendMessage",msgData);
2
3
4
5
6
7
- 参数1:tab主框架名称
- 参数2:消息发送命令
- 参数3:消息内容
接受方
//注册消息服务(自定义)
fox.navigator.registerMessageService("custom_message",(type,data)=>{
console.info("收到消息:"+data);
fox.layer.open("收到消息:"+data)
});
2
3
4
5
- 参数1:消息类型,对应消息内容的的eventType
- 参数2:消息处理函数
§ 5.4 共享存储
框架提供了多页面之间的内容存储,如下 存储内容
let message="当前时间是:"+(new Date()).format("yyyy-HH-dd hh:mm:ss");
fox.shareBus.put("global", "time", message);
fox.layer.open("存入数据:"+message);
2
3
读取内容
let msg= fox.shareBus.get("global", "time");
fox.layer.open(msg);
2
§ 5.5 webview tab页内容加载/回退
框架提供了加载内容和回退内容的接口 加载
fox.plus.to('http://www.163.com');
- 参数1:加载URL路径
回退
fox.plus.back();
§ 5.6 webview窗口打开/关闭
打开窗口
fox.plus.append(‘../tip/tip.html’);
- 参数1:加载URL路径
关闭当前窗口
fox.plus.remove();
关闭所有窗口
fox.plus.remove({all:true});
- 参数1:条件