`
lixw
  • 浏览: 200812 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Ext点滴

阅读更多

 

Ext.fly()正解

写道
Result: higher performance, lower memory usage.

You only need to keep in mind that you cannot keep Element returned by Ext.fly for later use as it's dom will sooner or later gets replaced by another one.
写道
仅在第一次调用Ext.fly时创建一个Flyweight对象(该对象包含了Element的所有操作接口)并将其缓存,之后的所有fly操作都只是修改该flyweight对象的dom属性,每次fly返回的结果都是共享的同一个flyweight对象。这样每次fly返回的Element相比 Ext.get而言,减少了每次创建Element时对大量的操作接口的创建。所有fly的对象都共享一套Element操作接口,内存占用自然少了很多,而且执行速度也得到了提升。在大量的创建操作中效果会更加明显。

由于fly的操作原理,我们不能将fly的返回结果保存在变量中以便重用,因为每次fly操作都将可能改变该变量的dom指向。

 

详见:http://www.ajaxbbs.net/post/extjs/Ext-fly-and-Ext-get.html

 

Ext.extend()实现继承

Ext API说明:

Ext.extend( Object subclass, Object superclass, [Object overrides] ) : void 

Extends one class with another class and optionally overrides members 
with the passed literal.  This class also adds the function "override()" to 
the class that can be used to override members on an instance. 

Parameters: 

subclass : Object The class inheriting the functionality
superclass : Object  The class being extended
overrides : Object  (optional) A literal with members

Returns: void 

 

示例:

var SubClass = function(config) {
	SubClass.superclass.constructor.call(this, config||{}); 
	//初始化部分
}; 
Ext.extend(SubClass, BaseClass, {
	//新增的方法
	newMethod : function() {
	},
	//覆盖父类的方法
	overriddenMethod : function() {
	} 
};

 

Ext.extend()的一个问题:数组属性在继承中复制的是引用造成混乱

http://www.cnblogs.com/beginor/archive/2008/03/22/1117790.html

 

实现Ext Grid宽高自适应

 

http://www.cnitblog.com/yemoo/archive/2008/05/30/44593.html

 

//..前面若干行代码省略,如ds/colmodel等
var orgGrid=Ext.get("orgGrid");  //展示grid的容器
    var grid = new Ext.grid.GridPanel({
        title:"人员管理",
        ds: ds,  //数据源
        cm: colModel,  //列模式
        sm:selMode,    //选择模式
        width:orgGrid.getComputedWidth(),
        height:orgGrid.getComputedHeight(),
        autoExpandColumn:"memory",  //自动扩展宽度的列
        autoScroll:true,
        loadMask:{msg:"数据加载中,请稍等"}
     });
     ds.load();
     grid.render(orgGrid);  //把grid铺到id为grid的容器中

window.onresize=function(){
        grid.setWidth(0);
        grid.setWidth(orgGrid.getComputedWidth());
};
 

 

关于设置Grid自适应列宽的讨论:

gygcloud写道
viewConfig{forceFit:true}是设置的grid内列的宽度
withoutmewang 写道
divname的宽度固定(100%也是固定的),则在初始化grid时,grid的宽度也是固定的。那么将grid渲染后,调整窗口大小,则grid不会随着窗口大小而变化。 举例:

<div id="divID" style="width:100%"></div>

var width = Ext.get("divID").getWidth();
alert(width);// 此时宽度为div的数字宽度。如1265

// 赋值到grid上相当于
new Ext.grid.GridPanel({
width: 1265....
});

我们调整整个IE窗口的大小,则会发现GridPanel还是撑出去了,因为它不是我们期望的100%

 

stworthy写道
设置grid自适应宽度,首先要清楚grid放在什么容器中,设置该容器的layout:fit就行了。比如页面上如果只放置一个grid,一般改成用Viewport,再在Viewport中包含grid就能解决问题了。

{
region:'center',
layout:'fit',
items:grid
}
cooleone 写道
如果items只有grid的话是可以的
但是我的应用里items有两个grid和一个form
这个时候就不起作用了

 

ecsun 写道
我最终的解决办法是这样子的:

var grid=new Ext.grid.GridPanel(...);

var view=new Ext.Viewport({
layout:'border',
renderTo:'topic-grid',
border:false,
items:[{
region:'center',
layout:'fit',
items:[grid]
}]
});

这个也是在extjs 上讨论过的做法,经过测试,在firfox中和在IE中显示的grid样式是一样的,不再出来宽度无限扩张的问题,可以按我们想要的方式被控制。
这里我比较懒,使用了fit,大伙可以改为其它的。

 

jimesum 写道
在GridPanel里加上 bodyStyle:'width:100%', 配置项就可以了

 

wangzi6hao 写道
var grid = new Ext.grid.GridPanel({
//autoWidth:true,
border:false,
width: Ext.get('center_context_desktop').getWidth(),
ds: new Ext.data.Store({
reader: new Ext.data.ArrayReader({}, [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]),
data: Ext.grid.dummyData
}),
cm: new Ext.grid.ColumnModel([
new Ext.grid.RowNumberer(),
{id:'company',header: "Company", width: 120, sortable: true, dataIndex: 'company'},
{header: "Price", width: 70, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
{header: "Change", width: 70, sortable: true, dataIndex: 'change'},
{header: "% Change", width: 70, sortable: true, dataIndex: 'pctChange'},
{header: "Last Updated", width: 95, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]),

viewConfig: {
forceFit:true
},
autoExpandColumn:'company'
});
//autoWidth:true,
这一行一定要隐藏,在ie7和ff下试了,是没有问题的.
同时还有bodyStyle:'width:100%',这个也试成功了
xugq035 写道
Ext.get("divname").getWidth() 和 bodyStyle:'width:100%' 都有问题,这只是设置了一个初始值,当窗体放大或缩小的时候它不会跟着变,用layout比较好

 

microboat 写道
对ext-all.css修正如下
/*grid宽度bug*/
.x-grid3-header-offset{width:auto;}

 

测试结果:

<!-- --><!-- --><!-- -->

序号

容器设置

自身设置

浏览器

表格数

描述

截图

1

 

 

IE6

1

宽度、高度都有问题

1.bmp

FF3

1

高度有问题

F1.bmp

2

 

bodyStyle : 'width:100%;'

IE6

1

高度有问题

2.bmp

FF3

1

高度有问题

F1.bmp

3

<div id="a" style='width:100%; height:100%'></div>

width : Ext.get('a').getWidth,

height : Ext.get('a').getHeight

IE6

1

出现两个列表、高度有问题

3.bmp

FF3

1

高度有问题

F1.bmp

4

<div id="a" style='width:100%; height:250px'></div>

width :

Ext.get('a').getComputedWidth,

height :

Ext.get('a').getComputedHeight

IE6

1

改变窗口大小时有问题

4.bmp

FF3

1

改变窗口大小时有问题

F4.bmp

5

 

bodyStyle : 'width:100%;height:100%'

IE6

1

 

 

FF3

1

 

 

6

layout : ‘fit’

bodyStyle : 'width:100%;'

IE6

1

 

 

FF3

1

 

 

7

layout : ‘fit’

bodyStyle : 'width:100%;'

IE6

2

高度有问题

1.bmp

FF3

2

高度有问题

F1.bmp

 结论:

  • 如果只有一个列表组件时候,设置它所属容器的layout : 'fit'是最理想的解决方法。
  • 如果页面上超过一个组件时候,我们不能使用1的方法,这会造成只显示一个组件,这时候可行的办法是指定父容器的layout : 'border',利用bodyStyle设定north或者south区域为固定高度(这个在FF3上好像不起作用),center区域会自适应。
  • 要设定列宽自适应,可以设置GridPanel的属性:autoExpandColumn 和设定viewConfig :{forceFit : true}来解决。

 

项目总结:

 

1、获取表单所有字段,并构造为Store查询参数传递:

var params = form.getValues(true);
var paramsArr = params.split("&");
for (var i = 0; i < paramsArr.length; i++) {
	var paramsField = paramsArr[i].split("=")[0];
	var paramsValue = paramsArr[i].split("=")[1];
	if (myStore.baseParams[paramsField]) {
		myStore.baseParams[paramsField] += ","
			+ decodeURI(paramsValue);
	} else {
		myStore.baseParams[paramsField] = decodeURI(paramsValue);
	}
}

myStore.load({
	params : {
		start : 0,
		limit : 20
	},
	callback : function() {
		//do something
	}
});

我们在使用了lovcombo扩展后,它获取到的值是以逗号分割的字符串,这时候我们需要对其中的‘%2C’进行转码,改造如下:

var prepareParamsFromForm = function(frm, store) {
	store.baseParams = {};

	var params = frm.getValues(true);
	// alert(params);

	var paramsArr = params.split("&");

	for (var i = 0; i < paramsArr.length; i++) {
		var paramsField = paramsArr[i].split("=")[0];
		var paramsValue = paramsArr[i].split("=")[1];
		if (!paramsValue) {
			continue;
		}

		paramsValue = decodeURI(paramsValue);
		// 替换所有%2C为逗号
		while ((paramsValue = paramsValue.replace('%2C', ',')).indexOf('%2C') != -1);

		if (store.baseParams[paramsField]) {
			store.baseParams[paramsField] += "," + paramsValue;
		} else {
			store.baseParams[paramsField] = paramsValue;
		}
	}
}
 

2、清空Gird中的复选框选中状态:

App.ui.SelModel = Ext.extend(Ext.grid.CheckboxSelectionModel, {
	initComponent : function() {
		Ext.apply(this, {
			header : '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"></div>',
			handleMouseDown : function(e) {
			},
			listeners : {
				'selectionchange' : function(e) {}
			}
		});
		App.ui.SelModel.superclass.initComponent.call(this);
	}
});

// 取消全选
var t = Ext.get('x-grid3-hd-checker');
if (t.dom.className == 'x-grid3-hd-checker') {
	var hd = Ext.fly(t.dom.parentNode);
	hd.removeClass('x-grid3-hd-checker-on');
}

 

3、解决Grid列中的ComboBox列显示值和提交值的问题:

var dsType = new Ext.data.SimpleStore({
	fields : ['id', 'name'],
	data : [['', '请选择'], ['1', '类型一'], ['2', '类型二']]
});

var selTypeId;
//.. 列定义
{
	header : '类型',
	dataIndex : 'typeId',
	sortable : true,
	editor : new Ext.form.ComboBox({
		typeAhead : true,
		triggerAction : 'all',
		valueField : 'id',
		displayField : 'name',
		mode : 'local',
		store : dsType,
		selectOnFocus : true,
		allowBlank : false,
		loadingText : '加载中...',
		listeners : {
			'select' : function(combo, record, index) {
                                  selTypeId = record.data.id; 
                        }
		}
	}),
	renderer : function(value, metadata, record, rowIndex, colIndex, store) {
		var targetIndex = dsType.find('id', value);
		if (targetIndex == -1) {
			return "无";
		} else {
			return dsType.getAt(targetIndex).get('name');
		}
	}
}

 

4、我们有这样的一个需求,有个字段的取值类型包括:等于、大于、大于等于、小于、小于等于、离散,根据不同的选择项我们会显示不同的输入框或者复选框,提供给用户,这个时候涉及到显示隐藏以及校验等内容,我们简单总结了一下:

{
				layout : 'table',
				layoutConfig : {
					columns : 12
				},
				items : [{
							html : '费用:',
							cls : 'self-label',
							baseCls : null
						}, {
							xtype : 'combo',
							name : 'cust.exclude',
							emptyText : '请选择',
							id : 'a',
							width : 108,
							readOnly : true,
							triggerAction : 'all',
							valueField : 'id',
							displayField : 'name',
							mode : 'local',
							store : new Ext.data.SimpleStore({
										fields : ['id', 'name'],
										data : [['', '请选择'], ['1', '等于'],
												['2', '大于'], ['3', '大于等于'],
												['4', '小于'], ['5', '小于等于'],
												['6', '介于'], ['7', '介于等于'],
												['8', '离散']]
									}),
							selectOnFocus : true
						}, {
							xtype : 'hidden',
							name : 'cust.aSign'
						}, {
							xtype : 'numberfield',
							id : 'a1',
							width : 60,
							style : 'margin-left:20px;display:none',
							name : 'cust.aBegin'
						}, {
							html : '到:',
							id : 'a2',
							style : 'margin-left:10px;display:none',
							baseCls : null
						}, {
							xtype : 'numberfield',
							id : 'a3',
							width : 60,
							vtype : 'range',
							style : 'display:none',
							name : 'cust.aEnd'
						}, {
							html : '高',
							id : 'a4',
							style : 'display:none',
							baseCls : null
						}, {
							xtype : 'checkbox',
							id : 'a5',
							inputValue : '2',
							style : 'display:none',
							name : 'cust.aD'
						}, {
							html : '中',
							id : 'a6',
							style : 'display:none',
							baseCls : null
						}, {
							xtype : 'checkbox',
							id : 'a7',
							inputValue : '1',
							style : 'display:none',
							name : 'cust.aD'
						}, {
							html : '低',
							id : 'a8',
							style : 'display:none',
							baseCls : null
						}, {
							xtype : 'checkbox',
							id : 'a9',
							inputValue : '0',
							style : 'display:none',
							name : 'cust.aD'
						}]

			}

添加事件:

		Ext.getCmp('a').addListener('select',
				function(combo, record, index) {
					var which = 'a';
					// 清空值
					for (var i = 1; i <= 9; i = i + 2) {
						if (i == 1 || i == 3) {
							Ext.get(which + i).set({
										value : ''
									});
						} else {
							Ext.get(which + i).set({
										checked : ''
									});
						}
					}

					this.form.findField('cust.aSign').setValue(record
							.get('id'));
					if (index == 0) {
						// 未选择
						for (var i = 1; i <= 9; i++) {
							Ext.get(which + i).hide();
						}
					} else if (index < 6) {
						// 等于,大于,大于等于,小于,小于等于
						Ext.get(which + "1").show();
						for (var i = 2; i <= 9; i++) {
							Ext.get(which + i).hide();
						}

					} else if (index > 5 && index < 8) {
						// 介于、介于等于
						for (var i = 1; i <= 3; i++) {
							Ext.get(which + i).show();
						}
						for (var i = 4; i <= 9; i++) {
							Ext.get(which + i).hide();
						}
					} else if (index == 8) {
						// 离散
						for (var i = 1; i <= 3; i++) {
							Ext.get(which + i).hide();
						}
						for (var i = 4; i <= 9; i++) {
							Ext.get(which + i).show();
						}
					}
				}, this);

我们看到对于a3,还有一个Vtype属性,这个是我们的一个自定义校验规则,代码如下:

		// 自定义校验规则,检查上界值应该大于下界值
		Ext.applyIf(Ext.form.VTypes, {
					"range" : function(value, field) {
						var bottomField = Ext.get('a1');
						if (bottomField) {
							if (parseInt(value) <= parseInt(bottomField.getValue())) {
								return false;
							}
						}
						return true;
					},
					"rangeText" : "上界值应该大于下界值"
				});

当然这个也存在问题,在监听事件中 我们查找元素用的是id,如果我们这个字段要在多个页面使用时,id重复会造成问题,可以考虑采用DOM的方式查找或者利用Ext.select()来查找,这样我们的这个Field才可以实现复用。

对于上面校验规则的修改:

// 自定义校验规则,检查上界值应该大于下界值
Ext.applyIf(Ext.form.VTypes, {
			"range" : function(value, field) {
				var eventId = field.id;				
				var targetId = field.bottomField;				
				var bottomField = Ext.get(targetId);
				if (bottomField) {
					if(value != '' && bottomField.getValue() != ''){
						if (parseInt(value) <= parseInt(bottomField.getValue())) {
							return false;
						}
					}
				}
				return true;
			},
			"rangeText" : "上界值应该大于下界值"
		});

注意这里,我们对上界值字段需要添加属性bottomField,它的取值为下界值字段对应的ID。

 

5、在开发过程中我们经常用到重新加载Grid数据的问题,利用store.removeAll()仍然存在一些问题,比如参数,总记录数显示,复选框选中状态未清空等问题,所以我们自定义方法来实现清空关联数据:

 

/**
 * 更新列表数据,包括更新分页
 * @param {} grid 列表组件
 * @param {} params 附加给数据集的查询参数,以{}的形式提供
 * @param {} callback 数据加载完成后的回调函数
 */
var updateGrid = function(grid, params, callback) {
	if (!grid) {
		Ext.MessageBox.alert("错误", "列表不存在");
		return;
	}
	
	var store = grid.getStore();
	if (!store) {
		Ext.log("错误", "列表的数据集不存在");
		return;
	}

	//清空复选框
	var sm = grid.getSelectionModel();
	if(sm){
		//sm.clearSelections();
		// 清空所有选择项和全选
		var t = Ext.get('x-grid3-hd-checker');
		if (t && t.dom.className == 'x-grid3-hd-checker') {
			var hd = Ext.fly(t.dom.parentNode);
			hd.removeClass('x-grid3-hd-checker-on');
			sm.clearSelections();
		} else {
			sm.clearSelections();
		}
       }
				
	var tbar = grid.getTopToolbar();
	var bbar = grid.getBottomToolbar();

	//清空数据集
	store.removeAll();

	//更新分页
	if (tbar) {
		tbar.updateInfo();
		tbar.afterTextEl.el.innerHTML = String.format("共 {0} 页", 1);
		tbar.first.setDisabled(true);
        tbar.prev.setDisabled(true);
        tbar.next.setDisabled(true);
        tbar.last.setDisabled(true);
        tbar.loading.disable();
	}
	if (bbar) {
		bbar.updateInfo();
		bbar.afterTextEl.el.innerHTML = String.format("共 {0} 页", 1);
		bbar.first.setDisabled(true);
        bbar.prev.setDisabled(true);
        bbar.next.setDisabled(true);
        bbar.last.setDisabled(true);
        bbar.loading.disable();
	}

	store.load({
				params : params ? params : {},
                callback : function() {
					////更新分页
					if (tbar) {
						tbar.updateInfo();
					}
					if (bbar) {
						bbar.updateInfo();
					}
					//执行回调
					if (callback && typeof(callback) == 'function') {
						callback();
					}
				}
			});
}

 

load()和reload()的区别:

 

下面是Ext2.0官方文档中的说明:

load( Object options ) : void 

Loads the Record cache from the configured Proxy using the configured Reader. 
If using remote paging, then the first load call must specify the start and 
limit properties in the options.params property to establish the initial position within the 
dataset, and the number of Records to cache on each read from the Proxy.

It is important to note that for remote data sources, loading is asynchronous, 
and this call will return before the new data has been loaded. 
Perform any post-processing in a callback function, or in a "load" event handler.

 

reload( [Object options] ) : void 

Reloads the Record cache from the configured Proxy using the configured Reader 
and the options from the last load operation performed. 

      从文档中可以看出reload使用最近的一次配置来装载数据。我们在应用中就遇到过这样一个问题,对于可编辑面板,我们总是在afteredit之后重新装载数据,之前使用了:

store.removeAll(); 
store.load({params : params, callback : callback});

这样如果我们在修改完一个cell后之后,不离开编辑状态,重新双击可编辑单元格时候就会报错。而且更有意思的是在IE上如果你到了另外一个页面,这个编辑状态依然存在,还能修改,返回这个面板同样会报错(Object Error)。经过思考发现时最开始的设计思路有问题,对于所有面板都是一次性显示的,而数据是延时加载的,不过由于时间紧迫,只能采取权宜之际,对于前面的问题,去掉removeAll操作,同时将load操作修改成reload操作;对于后面的问题,我们对于点击左侧树的响应事件中增加对于可编辑面板的stopEditing()方法,算是勉强解决了问题。

 

Ajax请求超时:

 Ext.Ajax.request()默认超时设置为30秒,我们如果想要一劳永逸的修改这个设置(比如压力测试情况下),因为Ext.Ajax是单实例对象(全局单一的),所有可通过这样的方式来设置:

Ext.Ajax.timeout = 3 * 30 * 1000;// 3分钟,默认为30秒

 

Ext监听键盘事件:

 

在实际的项目中,我们在登陆页面设定按回车键就提交Form表单,为此,我们添加了:

Ext.getDoc().addKeyListener(13, function(
    beforeSubmit('form1');
));

这个在首页表单提交中没有问题,但是进入到主页面(其实共用一个Javascript上下文) ,这时候按回车键会返回到首页面,原因是此时Document仍然监听回车键事件。

为此,我们在beforeSubmit()方法结束处添加了:

Ext.getDoc().removeAllListeners();

同样我们回车登入系统,这时候按回车是OK的,我们到了一有输入框的查询页面,光标定位在文本框中,按回车又回到了首页,这个就很疑惑了。

后来我们给这个查询条件输入框,增加了这样的事件相应:

Ext.getCmp('queryCondition').addListener('specialkey',
	function(field, ee) {
		if (ee.getKey() == Ext.EventObject.ENTER) {
			this.searchHandler();
			ee.stopEvent();
		}
	}, 
this);

在这个事件相应中,我们判断是否有回车键事件,如果有,执行查询,同时停止事件(stopEvent会停止默认事件的执行和事件的起泡传播)。

这时候我们再回来发现文本框的相应很令人满意。

究竟原因何在呢?等学习之后再补充,如果有输入理解的朋友不吝赐教!谢谢。

 

参考:Ext2中实现全页面键盘导航

分享到:
评论
1 楼 elemark 2010-10-26  
很有用,受教了

其中关于响应时间timeout的处理,帮了我的大忙,多谢多谢

相关推荐

    人人都玩开心网:Ext JS+Android+SSH整合开发 数据库文件

    - **案例背景**:“人人都玩开心网”可能是一款社交网络应用,旨在让用户能够轻松分享生活点滴,建立朋友之间的联系。 - **技术实现**:本书通过介绍如何使用Ext JS、Android以及SSH框架来实现该应用的具体功能,...

    Eclipse SWT开发点滴

    ### Eclipse SWT开发点滴 #### 一、第三方包的引用 在使用Eclipse进行SWT开发时,经常会遇到需要引入第三方库的情况。以下是引入第三方库的具体步骤: 1. **工程项目增加Libraries** - 右键点击项目 -&gt; `Build ...

    RedHat Linux用户管理经验点滴

    ### RedHat Linux用户管理经验点滴 #### 一、RedHat Linux简介及背景 RedHat Linux作为广受欢迎的Linux发行版之一,在企业级应用环境中占据着重要地位。它不仅提供了稳定可靠的系统性能,还具备丰富的软件资源和...

    java文集

    正则表达式 lucene索引合并 探查Weblogic JDBC Multipool 问题 struts通用Exception处理 Grails中默认数据库HSQLDB点滴 从request获取各种路径总结 DIV实现的表格自动伸张与收缩 java 邮件...

    安卓手机格式化怎么恢复,三星手机格式化数据恢复软件实用.pdf

    在现代生活中,手机已经成为了我们记录生活点滴的重要工具,尤其是智能手机如三星,它们不仅具备拍照功能,还能存储大量照片和其他重要数据。然而,有时由于误操作或者意外情况,可能会导致手机数据丢失,尤其是照片...

    口腔临床常用的各类简写.doc

    - **ivdirp**: Intravenous drip, please request the medicine,静脉点滴,请取药。 5. **度量单位与剂量**: - **MCg, MG, G, ML**: 微克、毫克、克、毫升,药物剂量单位。 - **sig**: Signification,指示,...

    flutter应用开发中文本输入框TextField的焦点获取控制篇

    —— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。 重要消息 精通点的可以查看这里 精述 Flutter 从入门实践到开发一个APP之UI基础篇 视频 flutter从入门 到精通 系列文章 TextField ...

    flutter应用程序开发中文本输入框TextField中输入文本 textAlign 对齐分析篇

    —— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。 重要消息 精通点的可以查看这里 精述 Flutter 从入门实践到开发一个APP之UI基础篇 视频 flutter从入门 到精通 系列文章 TextField ...

    常用处方缩写表.doc

    15. `I.h.`, `I.s.`, `I.m.`, `I.v.`, `I.v.derp.`, `I.v.drip.`, `I.v.gtt.`: 分别代表皮下注射、皮内注射、肌肉注射、静脉注射、静脉皮下注射、静脉点滴和静脉滴注。 16. `I.u.`: “国际单位”,用于计量某些生物...

Global site tag (gtag.js) - Google Analytics