深入浅出ExtJS 第六章 布局
6.1 布局的用途
6.1 布局的用途
//决定把什么东西放到什么位置;
var vieport = new Ext.Viewport({
layout:'border', //使用BorderLayout的布局方式(边界布局);可以自动检测浏览器的大小变化和自动调整布局中每个部分的大小;
items:[{
region:'north', //指定组件的具体位置;
height:40,
html:'<h1>顶部</h1>'
},{
region:'west',
width:100,
html:'<p>左侧区域</p>'
},{
region:'center',
html:'主要内容'
}]
});
//Ext的所有布局都是从Ext.Container开始的,Ext.Container的父类是Ext.BoxComponent;
//Ext.BoxComponent是一个盒子组件,可以定义宽度/高度和位置等; //Ext.Container及其子类
>.Ext.Container //Ext.Container的子类都可以用layout对内部的items进行布局;
>.Ext.Viewport
>.Ext.Panel
>.Ext.TabPanel
>.Ext.Tip
>.Ext.Window
>.Ext.form.FieldSet
>.Ext.form.FormPanel
>.Ext.tree.TreePanel
>.Ext.grid.GridPanel
>.Ext.grid.EditorGridPanel
>.Ext.grid.PropertyGrid //所有布局类也有一个共同的超类Ext.layout.ContainerLayout
//凡是该超类的子类都可以对Ext.Container及其子类进行布局定义;
>.Ext.layout.ContainerLayout //容器布局
>.Ext.layout.AnchorLayout //锚点布局
>.Ext.layout.AbsoluteLayout //绝对定位布局
>.Ext.layout.FormLayout //表单布局
>.Ext.layout.BorderLayout //边框布局
>.Ext.layout.ColumnLayout //分列布局
>.Ext.layout.FitLayout //自适应布局
>.Ext.layout.Accordion //折叠布局
>.Ext.layout.CardLayout //卡片布局
>.Ext.layout.TableLayout //表格布局
6.2 最简单的布局--FitLayout
6.2 最简单的布局--FitLayout
//自动适应页面大小
Ext.onReady(function(){
var store = new Ext.data.ArrayStore({
fields:['id','name','desc'],
data:[['1','name1','desc1']] //数据存储器;
}); var grid = new Ext.grid.GridPanel({ //创建带数据的表格;
title:'grid',
viewConfig:{forceFit:true},
store:store,
columns:[
{header:'id',dataIndex:'id'},
{header:'名称',dataIndex:'name'},
{header:'描述',dataIndex:'desc'}
],
tbar:new Ext.Toolbar(['添加','修改','删除']),
bbar:new Ext.PagingToolbar({
pageSize:15,
store:store
})
}); var viewport = new Ext.Viewport({
layout:'fit', //指向自适应布局;
items:[grid] //将表格引入布局;
});
});
6.3 常用的边框布局--BorderLayout
6.3 常用的边框布局--BorderLayout
//FitLayout每次只能使用一个子组件;而现实中我们使用最多的是Ext.layout.BorderLayout布局;
var viewport = new Ext.Viewport({
layout:'border', //指向为BorderLayout布局;
items:[
{region:'north',html:'north',height:120}, //region:指定组件的位置;html:组件内容;
{region:'south',html:'south',height:30},
{region:'west',html:'west',width:40},
{region:'east',html:'east',width:100},
{region:'center',html:'center'} //center的大小是其他4个部分设置好之后计算出来的;不可以省略;
]
}); 6.3.1 设置子区域的大小
//可以直接设置north与south的高度和west与east的宽度; 6.3.2 使用split并限制它的的范围
//使用split参数,用户可以自行拖放来改变某一个区域的大小;
//使用minSize和maxSize将限制用户拖放的范围;
var viewport = new Ext.Viewport({
layout:'border',
items:[
{region:'north',html:'north',split:true}, //顶部可以上下拖动改变大小;
{region:'west',html:'west',width:100,split:true,minSize:80,maxSize:120},
//左侧可以左右拖动改变大小; 但宽度的范围在80~120之间;
{region:'center',html:'center'}
]
}); 6.3.3 子区域的展开和折叠--collapsible
//属性collapsible:true;这个属性激活了区域折叠功能;
//title:'west';折叠区域的标题;必须跟collapsible一起设置;
items:[
{region:'north',html:'north',heith:100,title:'顶部',collapsible:true},
...
]
6.4 制作伸缩菜单布局--Accordion(折叠布局)
6.4 制作伸缩菜单布局--Accordion(折叠布局)
//BorderLayout布局下嵌套的Accordion布局;
var viewport = new Ext.Viewport({
layout:'border', //第一层是BorderLayout布局;
items:[{
region:'west', //子组件左侧区域;
width:200,
layout:'accordion', //子组件是Accordion(折叠)布局;
split:true,
layoutConfig:{ //布局配置信息;
titleCollapse:true, //点击标题也可折叠;
animate:true, //折叠动画;
activeOnTop:false //打开的组件是否置顶;
},
items:[{ //孙组件;折叠布局;
title:'第一栏',
html:'第一栏'
},{
title:'第二栏',
html:'第二栏'
}]
},{
region:'center', //子组件center区域;
html:'center区域'
}]
});
6.5 实现操作向导的布局--CardLayout
6.5 实现操作向导的布局--CardLayout
//为CardLayout配置几个子面板,每次只显示其中一个;
var viewport = new Ext.Viewport({
layout:'border',
items:[{
region:'west',
id:'wizard',
width:200,
title:'xx向导',
layout:'card',
activeItem:0,
bodyStyle:'padding:15px',
defaults:{
border:false
},
bbar:[{
id:'move-prev',
text:'上一步',
handler:function(){
navHandler(-1);
},
disabled:true
},'->',{
id:'move-next',
text:'下一步',
handler:function(){
navHandler(1);
},
}],
items:[{
id:'card-0',
html:'<h1>欢迎使用向导</h1><p>1/3</p>'
},{
id:'card-1',
html:'<p>2/3</p>'
},{
id:'card-2',
html:'<p>完成</p>'
}]
},{
region:'center',
split:true,
border:true
}]
});
//设置navHandler函数 (带注释!)
var navHandler = function(direction){
var wizard = Ext.getCmp('wizard').layout;
var prev = Ext.getCmp('move-prev');
var next = Ext.getCmp('move-next');
var activedId = wizard.activeItem.id;
if(activeId == 'card-0'){
if(direction == 1){
wizard.setActiveItem(1);
prev.setDisabled(false);
}
}else if(activeId == 'card-1'){
if(direction == -1){
wizard.setActiveItem(0);
prev.setDisabled(true);
}else{
wizard.setActiveItem(2);
next.setDisabled(true);
}
}else if(activeId == 'card-2'){
if(direction == -1){
wizard.setActiveItem(1);
next.setDisabled(false);
}
}
};
6.6 控制位置和大小的布局--AnchorLayout和AbsolluteLayout
6.6 控制位置和大小的布局--AnchorLayout和AbsolluteLayout
//AnchorLayout提供了灵活的布局方式,既可以为items中的每个组件指定与总体布局大小的差值;也可以设置一个比例使子组件可以根据整体自行计算本身的大小;
>1.使用百分比进行配置
//设置某一个子组件占整体长和宽的百分比;
var viewport = new Ext.Viewport({
layout:'anchor', //设置接下来的子组件都为AnchorLayout布局;
items:[{
title:'panel1',
html:'panel1',
anchor:'50% 50%' //panel1组件占总体宽度的50%和高度的50%;
},{
title:'panel2',
html:'panel2',
anchor:'80%' //panel2组件占总体宽度的80%,高度自适应;
}]
});
>2.设置与右侧和底部的边距;
var viewport = new Ext.Viewport({
layout:'anchor',
items:[{
title:'panel1',
html:'panel1',
anchor:'-50 -200' //组件与右侧和底部的相对(绝对)距离;
},{
title:'panel2',
html:'panel2',
anchor:'-100' //组件与右侧的距离;
}]
});
>3.side布局;
//在设置父组件和布局内部子组件都设置好width/height和anchorSize属性的前提下;AnchorLayout会记录布局整体与子组件在大小上的差值,为以后调整布局提供依据;
var viewport = new Ext.Viewport({
layout:'anchor',
anchorSize:{width:400,height:300},
//这是一个包含宽度和高度信息的JSON对象;以此作为以后计算差值的基准;
items:[{
title:'panel1',
html:'panel1',
width:200,
height:100,
anchor:'r b'
},{
title:'panel2',
html:'panel2',
width:100,
height:200,
anchor:'r b'
}]
});
//AnchorLayout首先获得父组件的宽度/高度,以及每个子组件的宽度/高度,然后将子组件与父组件的宽度/高度之差分别保存起来;根据改变后父组件的大小,计算出子组件当前的宽度和高度;
>4.同时使用百分比和边距
var viewport = new Ext.Viewport({
layout:'anchor',
items:[{
title:'panel1',
html:'panel1',
anchor:'-100 40%' //组件距右侧100px不变,高度是整体的40%;
},{
title:'panel2',
html:'panel2',
anchor:'-200 60%' //同上;
}]
});
>5.利用AbsoluteLayout进行绝对定位
//AbsoluteLayout是AnchorLayout的一个子类;继承了AnchorLayout的所有特性;
//AnchorLayout布局下的子组件都是自上而下竖直排列的;而AbsoluteLayout正是可以解决这个问题;
var viewport = new Ext.Viewport({
layout:'absolute',
//以下组件进行绝对定位;并使用AnchorLayout确定每个组件的相对大小;
items:[{
title:'panel1',
html:'panel1',
x:50, //子组件左上角距父组件的距离;
y:0,
anchor:'-200 40%' //子组件相对于父组件的大小;
}]
});
6.7 表单专用的布局--FormLayout
6.7 表单专用的布局--FormLayout
var viewport = new Ext.Viewport({
layout:'fit', //组件自适应填满布局;
items:[{
xtype:'form',
title:'信息',
labelAlign:'right', //控件标签右对齐;
labelWidth:50, //控件宽度;
frame:true, //圆角;
defaultType:'textfield',//以下组件为文本框控件;
items:[{
fieldLabel:'名称',
name:'name',
anchor:'90%' //占整体90%的空间;
},{
fieldLabel:'生日',
name:'birthday',
xtype:'datefield', //日期控件;
anchor:'90%'
},{
fieldLabel:'备注',
name:'desc',
xtype:'textarea', //多行文本控件;
anchor:'90% -100' //占整体90%;并且距离底部100px;
}]
}]
});
6.8 分列布局--ColumnLayout
6.8 分列布局--ColumnLayout
//ColumnLayout是将整个容器进行竖直切分的布局方式;
>1.使用ColumnLayout实现简单布局
var viewport = new Ext.Viewport({
layout:'column', //分列布局;
items:[{
title:'Column1',
columnWidth:.25
},{
title:'Column2',
columnWidth:.4
},{
title:'Column3',
columnWidth:.35
}]
});
>2.使用columnWidth平分剩余的宽度
var view = new Ext.Viewport({
layout:'column',
items:[{
title:'1',
width:20 //组件一宽度不变;
},{
title:'2',
columnWidth:.7 //宽度为剩下的70%;
},{
title:'3',
columnWidth:.3
}]
});
6.9 表格状布局--TableLayout
6.9 表格状布局--TableLayout
var view = new Ext.Viewport({
layout:'fit',
items:[{
title:'Table Layout',
layout:'table', //表格布局;
default:{
bodyStyle:'padding:20px'
},
layoutConfig:{
columns:3
},
items:[{
html:'<p>A</p>',
rowspan:2 //合并的行数;
},{
html:'<p>B</p>',
colspan:2 //合并的列数;
},{
html:'<p>C</p>',
cellId:'haha' //设置单元格ID;
},{
html:'<p>D</p>'
}]
}]
});
6.10 BoxLayout--HBox
6.10 BoxLayout--HBox
//横排一行多个组件;
var panel = new Ext.Panel({
title:'HBox',
width:400,
height:200,
renderTo:'grid',
layout:{
type:'hbox', //指定当前的Panel使用HBox布局方式;
padding:'5',
align:'stretch' //为组件设置统一的对齐方式;自动充满外部容器的大小;
},
defaults:{margins:'0 0 5 0 '},
items:[{
xtype:'button', //按钮组件;
text:'Button1',
flex:1
},{
xtype:'button',
text:'Button2',
flex:3 //值越大,对应的组件占据的空间越大;
}]
});
6.11 BoxLayout--VBox
6.11 BoxLayout--VBox
//竖排一列多个组件;
var panel = new Ext.Panel({
..
layout:{
type:'vbox', //指定当前的Panel使用HBox布局方式;
padding:'5',
align:'stretch'
},
items:[...]
});
6.12 Ext.TabPanel
6.12 Ext.TabPanel
//Tab布局组件
>1.普通Tab
var tabs = new Ext.TabPanel({ //创建TabPanel对象;
renderTo:document.body, //渲染到指定位置;
height:100
});
//任意组件直接使用add()函数便可添加到Ext.TabPanel中;
tabs.add({ //若不特别指定xtype,就会默认使用Ext.Panel为这些内容生成子面板;
id:Ext.id(), //使用Ext.id()函数生成唯一的id值;
title:'标题2',
html:'内容2',
closable:true //生成的标签受否可以手动关闭;
});
tabs.activate(0); //让指定的标签变成激活状态;参数是标签的索引值; >2.添加创建的Tab按钮
//添加两个按钮,用于新建包含表格的标签和包含Panel的标签
var tabs = new Ext.TabPanel({
height:200,
renderTo:'tab',
enableTabScroll:true
});
tabs.add({
title:'标题一',
html:'内容一',
closable:true
});
tabs.setActiveTab(0); var addGrid = new Ext.Button({ //创建按钮;
text:'添加一个grid',
renderTo:'add-grid',
handler:function(){ //"新建"按钮回调函数;
var id = Ext.id();
//创建表格↓↓↓↓↓↓↓↓↓↓↓↓↓↓
var grid = new Ext.grid.GridPanel({
store:new Ext.data.SimpleStore({
fields:['id','name'],
data:[
['1','name1'],
['2','name2'],
]
}),
columns:[
{header:'序号',dataIndex:'id'},
{header:'名称',dataIndex:'name'}
]
});
//将表格组件放入到tabs里↓↓↓↓
var tab = tabs.add({
title:'表格'+id,
closable:true,
layout:'fit',
items:[grid]
});
//激活当前的tab标签↓↓↓↓
tabs.setActiveTab(tab);
}
}); var addPanel = new Ext.Button({
text:'添加一个panel',
renderTo:'add-panel',
handler:function(){
var id = Ext.id();
var panel = new Ext.Panel({ //创建Panel标签;
html:'创建Panel标签成功'
});
var tab2 = tabs.add({
title:'Panel'+id,
closable:true,
layout:'fit',
items:[panel]
});
tabs.setActiveTab(tab2);
}
}); >3.执行从后台得到的HTML(包含JS脚本)
tabs.add({
title:'从后台获取内容',
autoLoad:{url:'xxx.html',scripts:true}
//autoLoad:创建后自动执行;默认是延迟加载的;
//scripts:执行得到的HTML里的脚本;
}) 6.12.1 标签面板的滚动菜单
//TabPanel的组件,可以在标签过多的时候显示一个下拉菜单;
//需引入tabs下的TabScrollMenu.js和TabScrollMenu.css;
var scrollerMenu = new Ext.ux.TabScrollerMenu({
maxText:15,
pageSize:5
});
var tabs = new Ext.TabPanel({
width:400,
height:200,
activeTab:0,
enableTabScroll:true,
resizeTabs:true,
minTabWidth:75,
frame:true,
plugins:[srcrooerMenu], //标签过多时显示下拉菜单;
items:[{title:'第一个tab'}],
renderTo:'tabs'
});
6.13 与布局相关的知识
6.13 与布局相关的知识
6.13.1 超类Ext.Container的公共配置与xtype的概念
>1.Ext.Container是所有可布局组件的超类;只要继承它的子类都可以对自身进行布局;
>2.主要参数:
>.layout(组件布局方式);
>.items(包含的子组件);
>3.与上面对应的还有两个参数:
>.layoutConfig:为布局提供特定的配置参数;
//在实例化过程中当前类会把自身的layoutConfig参数赋予layout对象并进行配置;
>.activeItem:表示当前显示哪一个子组件;
4.defaultType参数
>.当子组件没有指定xtype参数时,就会使用上级组建中设置的defaultType来作为自身的xtype;
//默认情况下是defaultType:'panel',也就是在items中创建的每个子组件都是Ext.Panel的实例;
//若需要其他类型的组件,直接替换成对应的类型的值即可;
5.xtype
//在Ext中,xtype:'grid'和new Ext.grid.GridPanel()是等价的;
items:[{
xtype:'grid',
store:store,
columns:columns
}]
//整体布局时,使用xtype更方便,结构也更清晰;
items:[new Ext.grid.GridPanel({
store:store,
columns:columns
})]
//创建实例的方式更适用于需要对某一部分进行详细配置的情况; 6.13.2 layout的超类Ext.layout.ContainerLayout
//当layout:'auto'时,就表示将使用Ext.layout.ContainerLayout的布局; 6.13.3 不指定任何布局时会发生的情况
>.组件默认使用的布局类型
Ext.Container Ext.layout.ContainerLayout
Ext.Viewport Ext.layout.ContainerLayout
Ext.Panel Ext.layout.ContainerLayout
Ext.TabPanel Ext.layout.CardLayout
Ext.Tip Ext.layout.ContainerLayout
Ext.Window Ext.layout.ContainerLayout
Ext.form.FieldSet Ext.layout.FormPanel
Ext.form.FormPanel Ext.layout.FormPanel
Ext.tree.TreePanel Ext.layout.ContainerLayout
Ext.grid.GridPanel Ext.layout.ContainerLayout
Ext.grid.EditorGridPanel Ext.layout.ContainerLayout
Ext.grid.PropertyPanel Ext.layout.ContainerLayout 6.13.4 使用Viewport对整个页面进行布局
//以上示例中,都是用Ext.Viewport对整个页面进行统一布局;
//实际上,Viewport只是一个用于整页布局的快捷工具类;
//多个Viewport之间会冲突; 6.13.5 使用嵌套实现复杂布局
Ext.onReady(function(){ //表格配置
var columns = [
{header:'编号',dataIndex:'id'},
{header:'名称',dataIndex:'name'},
{header:'描述',dataIndex:'descn'}
];
var data = [
['1','name1','descn1'],
['2','name2','descn2']
];
var store = new Ext.data.ArrayStore({
data:data,
fields:[
{name:'id'},
{name:'name'},
{name:'descn'}
]
});
store.load();
var grid = new Ext.grid.GridPanel({
store:store,
columns:columns,
title:'center-north',
region:'north' //此表格会在Panel布局的上方;
}); //树形配置
var tree = new Ext.tree.TreePanel({
store:new Ext.data.TreeStore({
proxy:{
type:'ajax',
url:'xxx.html'
},
root:{
expand:true,
text:'我是根'
}
}),
title:'west',
region:'west', //此树形组件会在Panel布局的左侧;
split:true,
border:true,
collapsible:true,
width:120,
minSize:80,
maxSize:200
}); //表单配置
var form = new Ext.form.FormPanel({
defaultType:'textfield',
labelAlign:'right',
title:'form',
labelWidth:50,
frame:true,
width:220,
title:'center-center',
region:'center', //此表单组件会在Panel布局的中间;
items:[{
fieldLabel:'文本框',
anchor:'90%'
}],
button:[{
text:'按钮'
}]
}); //布局开始
var viewport = new Ext.Viewport({
layout:'border',
items:[{
region:'north',
contentEl:'north-div', //上布局为id='north-div'的DIV;通过contentEl来指定HTML中显示的内容;
heith:80,
bodyStyle:'background-color:#BBCCEE;'
},{
region:'south', //下布局为id='south-div'的DIV
contentEl:'south-div',
height:20,
bodyStyle:'background-color:#BBCCEE;'
},tree,{ //左侧布局;树形;
region:'center', //中间布局;
split:true,
border:true,
layout:'border', //中间区域使用边界布局;
items:[gird,form] //将准备好的表格和表单引入中间布局区域;
}]
});
});
<div id='north-div'>标题栏:viewport加panel实现复杂布局</div>
<div id='south-div'>状态栏:Copyright by www.xxx.com</div> //这个Viewport中的每个子组件都是Panel类型;而Panel包含:TreePanel/GridPanel/FormPanel
//所以Panel的配置参数它们也都可以用;
//在任何一个Panel里设置layout:'border',就可以将它再次分成5各区域;并用region参数指定各自所在位置;
Viewport Panel
north:north-div;
south:south-div;
west:tree;
center:Panel;
north:grid;
center:form;
深入浅出ExtJS 第六章 布局的更多相关文章
- Android的学习第六章(布局一TableLayout)
今天我们来简单的说一下Android不居中的TableLayout布局(表格布局) 表格布局的意思就是将我们的布局看做为一个表格,主要用于对控件进行整齐排列 我们看一个简单的案例 <TableL ...
- Android的学习第六章(布局二--RelativeLayout)
今天我们来说一下Android布局中的Relativelayout布局(相对布局) 根据英译过来意思是相对布局,很容易理解,这一样布局使用的是元素与元素之间的微调做到布局的 含义:通过元素与元素之间的 ...
- Android的学习第六章(布局一LinearLayout)
今天我们来说一下Android五大布局-LinearLayout布局(线性布局) 含义:线性布局,顾名思义,指的是整个Android布局中的控件摆放方式是以线性的方式摆放的, 主要作用:主要对整个界面 ...
- 深入浅出ExtJS 第七章 弹出窗口
7.1 Ext.MessageBox 7.1 Ext.MessageBox //Ext.MessageBox为我们提供的alert/confirm/prompt等完全可以代替浏览器原生; 7.1.1 ...
- 深入浅出ExtJS 第五章 树形结构
5.1 TreePanel的基本使用 //树是一种非常典型的数据结构; 5.1.1 创建一棵树 //树控件有Ext.tree.TreePanel类定义,控件的名称为TreePanel;TreePane ...
- 深入浅出ExtJS 第四章 表单与输入控件
4.1 制作表单 var form = new Ext.form.FormPanel({ title:'form', defaultType:'textfield', buttonAlign:'cen ...
- 深入浅出ExtJS 第三章 表格控件
3.1 表格的特性简介 >.Ext中的表格功能:包括排序/缓存/拖动/隐藏某一列/自动显示行号/列汇总/单元格编辑等实用功能; >.表格由类Ext.grid.GridPanel定义,继承自 ...
- Qt Gui 第六章布局管理
1.QRadioButton之间如何互斥 其中一种方法是将各个QRadioButton控件放在同一个toolbarsLayout或者toolbarsGroupBox即可:如下所示 toolbarsGr ...
- 无废话ExtJs 入门教程十六[页面布局:Layout]
无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...
随机推荐
- gitignore无效最简单解决办法
git rm --cached 文件或者文件夹 git commit 提交 git push 提交
- nodejs以及npm的安装
参考资料:http://xiaoyaojones.blog.163.com/blog/static/28370125201351501113581/ 上面的仁兄说的比较清楚,基本解决了安装中遇到的问题 ...
- IOS开发之路四(UITabBarController)
前两天看了看斯坦福大学的iphone开发公开课,讲的倒是不错,可看的我云里雾里的,不怎么讲基础和原理,不太适合初学者.今天看了一上午ios5基础教程这本书感觉有点头绪了....废话少说,讲一讲我上午做 ...
- missing artifact com.oracle:ojdbc14:jar:10.2.0.2.0解决办法
下载jar,导入到maven中 下载:http://download.csdn.net/detail/spring123tt/6991897 cmd中输入: mvn install:install-f ...
- TMS3705A PCF7991AT 线路图
- 玩转iOS开发 - 多线程开发
前言 本文主要介绍iOS多线程开发中使用的主要技术:NSOperation, GCD. NSThread, pthread. 内容依照开发中的优先推荐使用的顺序进行介绍,涉及多线程底层知识比較多的NS ...
- PP常见数据表
Table表 Short text短文本 AFFL Work order sequence加工单顺序 AFFT Order process instructions订单-流程指令 A ...
- HDU 4286 Data Handler 双向链表/Splay
Data Handler Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...
- TP复习9
配置文件 'TMPL_TEMPLATE_SUFFIX'=>'.html',//更改模板文件后缀名'TMPL_FILE_DEPR'=>'_',//修改模板文件目录层次'TMPL_DETECT ...
- HTML <base> 标签
定义和用法 <base> 标签为页面上的所有链接规定默认地址或默认目标. 通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白. 使用 <base& ...