shenang博客技术文档


理论不懂就实践,实践不会就学理论!

posts - 35,comments - 55,trackbacks - 0
 

YUI中文文档

 

根据网上别人的说明和综合各方面资料,网上说的要么结构不是很清楚,要么不是很全,呵呵,借别人的轮子总结一下哈,不用造轮子了,我对YUI的文档作一个总结,共同学习。.

打算从零开始学习YUI AJAX类库那么多,为什么我要学习YUI呢?首先,因为YUI很强大;其次因为YUIYahoo! 的。虽然Yahoo!现在好像没落了,但听同事说了YUI的强大,抑制不住学习的兴奋,今天就来学习一下!学习的东西很多,今天只是走马观花的看一个大概的说明,即每个控件有什么功能,具体怎么用就是后面的事情了。

Yahoo发表了一系列的Ajax设计模式. Yahoo的这些工具包是Yahoo在收购了多个Web2.0网站后推出的Ajax工具包,代码的注释也写的很好,文档也很丰富和详尽。

YUI分为两个大类,一个是Ajax组件,里面包括对底层javascript包装后的几个工具包,分别是connection,event, dom,animation,dnd.还包括一组高级的javascript控件,目前包括AutoComplete,Calendar, Container,Menu,Slider,TreeView.

另一类是几个很有用的几个CSS文件,一个是CSS Page Grids,用它可以很方便的布局你的网页。另外两个是Standard CSS FontsStandard CSS Reset,利用这两个CSS可以对字体等在不同浏览器中获得一致的效果.

一、YUI Utilities(Connection Manager)

    Yahoojavascript文件都有一个注释的很好的,格式化很好的版本和一个去掉注释和空格的版本,学习看源代码当然用前者,而最后在网页上使用的时候就可以选用后者。

Connection的引入:

<!-- Dependency -->

build/yahoo/yahoo-min.js

<!—可选项: 用到事件时引入 -->

build/event/event-min.js

build/connection/connection-min.js

1. Connection Manager

这个工具包用来管理XMLHttpRequest,通过这个工具包可以查询正在执行的请求的状态,可以注册正确返回的回调函数,错误处理的回调函数,还可以根据提供的表单Id方便的收集和发送表单字段。下面给出的代码是基本调用形式

var callback =

{

success: function(res) {/*success handler code*/}, //正常返回处理函数

failure: function(res) {/*failure handler code*/}, //出错返回处理函数

argument: [argument1, argument2, argument3] //可以在success函数和failure函数中访问的变量

}

var transaction = YAHOO.util.Connect.asyncRequest(’GET’, sUrl, callback, null);

说明:

1、第一个参数:指明http请求的方式,可用的方式包括GETPOSTHEADPUTDELETE,但PUTDELETE可能在一些A级浏览器上不支持。

第二个参数:请求的URL

第三个参数:回调函数,用于服务器返回数据时调用的客户端处理程序

第四个参数:POST方式时,提供给URLPOST参数信息。

定义回调函数

2在异步事物中,可以创建回调函数处理服务器的响应和相关数据,如果你不关心服务器的返回信息,也可以忽略这些回调函数,所有这些回调函数对象都是可选的,然而在大多数情况下,应该至少提供以下三个回调函数:

success:服务器做出有效响应时的回调函数

failure:服务器响应了但提供了错误信息时的回调函数

argumentsuccessfailure为了处理返回信息需要的参数,可以是对象、字符串、数字或者包含了数据的数组。

3下面的表给出的是通过正确返回时res参数可以获得的属性值。

属性名                   描述

tId                      该Http请求的事务表示

status                   返回的Http状态码

statusText               对应状态码的字符串表示

getResponseHeader[label] 返回label名称标识的Http头的值

getAllResponseHeader     所有的Http头的字符串表示,用”"n”分隔

responseText             返回内容的字符串表示

responseXML              返回内容的XML表示

argument                 回调函数中传入的变量

错误返回时可以通过res返回的属性

属性名           描述

tId               该Http请求的事务表示

status            0

statusText       “communication failure”

argument          回调函数中传入的变量

4、在使用YAHOO.util.Connect.setForm上载文件时,需要定义upload回调函数代替successfailure

5、在回调函数中this将失去作用范围,这种情况下需要通过一个指向父对象的引用的数来访问对象的成员。为了能够使用对象的方法作为回调函数,并维持成员的作用范围,需要定义回调函数对象的成员scope,作为this的值。

6、如果想发送的是表单数据,那么使用下面的代码就可以了:

YAHOO.util.Connect.setForm(formId);

var cObj = YAHOO.util.Connect.asyncRequest(’POST’, ‘http://www.yahoo.com’, callback);

查看请求是否已经处理完

var cObj = YAHOO.util.Connect.asyncRequest(’GET’,''http://www.yahoo.com’,callback);

var callStatus = YAHOO.util.Connect.isCallInProgress(cObj);

超时取消请求

var cObj = YAHOO.util.Connect.asyncRequest(’GET’, sUrl, callback);

setTimeout(”YAHOO.util.Connect.abort(cObj)”,10000);

二、YUI Utilities(Event)

<!-- Dependency -->

build/yahoo/yahoo-min.js

<!-- Event source file -->

build/event/event-min.js

 EventCustom Event分别定义在YAHOO.util.EventYAHOO.util.CustomEvent

使用Event工具包可以简化浏览器端的事件驱动程序的开发,通过使用简单的接口可以订制响应DOM事件的代码,同时获得浏览器Event对象的各种属性也很方便。通过Event工具包我们还可以订制自己的事件,这样页面组件可以接收这些事件并做出响应。

Event工具集提供的方法

YAHOO.util.Event.addListener(element,eventType,fn,obj,override)

参数:

element:为绑定事件的元素id可以是一个数组,以支持批量操作

eventType:为事件类型

fn:为事件响应的回调函数

obj:当overridetrue时,为回调函数传入的参数对象;当overridefalse时,该参数被忽略。

override

返回值类型:Boolean

功能:给指定的element绑定事件响应函数

YAHOO.util.Event.removeListener:function(element,eventType,fn)

参数:

element:为绑定事件的元素id,

eventType:事件类型

fn:为事件响应函数

返回值类型:Boolean

功能:给指定的element解除绑定事件

YAHOO.util.Event.purgeElement ( el , recurse , sType )

参数:

el:为绑定事件的元素id,

recurseBoolean值,是否解除子节点的事件绑定

sType:事件类型

返回值类型:Boolean

功能:给指定的element解除绑定的同一类型的事件,也可以解除子节点上绑定的这一类型的事件

YAHOO.util.on

addListener的函数别名

YAHOO.util.Event.onAvailable ( p_id , p_fn , p_obj , p_override )

参数:

p_id:为绑定事件的元素id,

p_fn:为事件响应函数

p_obj:同addListenerobj参数

p_override:同addListeneroverride参数

返回值类型:

功能:当指定的elementp_id出现时,执行事件响应函数。如果在页面初始化之前执行这一函数,当页面加载时(可能还未完成时),就会执行响应的事件响应函数;如果放在页面加载之后执行这一函数,将以固定的时间轮询,当element可用时响应这一事件。这个轮询的的时间是可以配置的,缺省的时间是10秒一次。

YAHOO.util.Event.onContentReady ( p_id , p_fn , p_obj , p_override )

参数:

p_id:为绑定事件的元素id,

p_fn:为事件响应函数

p_obj:同addListenerobj参数

p_override:同addListeneroverride参数

返回值类型:

功能:onAvailable类似,但不同的是事件响应函数是等到element可以安全的修改的时候才响应。

YAHOO.util.Event.onDOMReady ( p_fn , p_obj , p_scope )

参数:

p_fn:为事件响应函数

p_obj:同addListenerobj参数

p_scope:同addListeneroverride参数

返回值类型:

功能:DOM第一次可用时执行响应函数。

YAHOO.util.Event.preventDefault ( event)

参数:

event:事件对象

返回值类型:

功能:阻止事件的缺省行为发生。

YAHOO.util.Event.getListeners ( el , sType )

参数:

elHTML element

sType:事件类型,String类型

返回值类型:Object{

type:事件类型

 fnaddListener添加的事件响应函数

 obj:提供给事件响应函数的参数对象

 adjust:否获取缺省的事件监听器

 indexUI事件监听器列表中的位置

}

功能:阻止事件的缺省行为发生。

YAHOO.util.Event.getTime( event)

参数:

event:事件对象

返回值类型:Date对象

功能:获取事件发生时的时间。

YAHOO.util.Event.getTarget(ev , resolveTextNode)

参数:

evt:事件对象

resolveTextNode

返回值类型: HTML element

功能:获取事件发生时的页面标签。对于IEwindow.event.srcElement

基本的事件代码

 

var oElement = document.getElementById(elementid);//获得事件源

function fnCallback(e) { alert(click); }//定义回调函数

YAHOO.util.Event.addListener(oElement, click, fnCallback);//注册回调函数,当oElementclick事件发生的时候,fnCallback函数将被调用。

//或者更简单的直接传递Id YAHOO.util.Event.addListener(elementid, click, fnCallback);

注册响应多个页面元素的事件

var ids = [el1, el2, el3];//该数组中可以包括元素ID,元素的引用,或者两者混合的情况。

function fnCallback(e) { alert(this.id); }

YAHOO.util.Event.addListener(ids, “click”, fnCallback);

YuiEvent包解决了一些比较实际的问题,第一页面元素通常在Javacript注册事件代码后载入,这个时候Yui会正确延迟注册,直到指Id的元素可以访问。第二微软的IE浏览器在事件处理函数中的this指向的是Window对象,而不是发生事件的那个元素,YUI也会正确的传递事件发生的源元素。第三可以把任意的对象传递给事件处理函数。

创建和使用自定义的事件

1.使用CustomerEvent对象创建自己的事件

function TestObj(name) {

this.name = name;

this.event1 = new YAHOO.util.CustomEvent(event1, this);

}

YAHOO.util.CustomEvent = function(type, oScope);

type表示事件类型的字符串

2。注册对自定义事件的响应函数

function Consumer(name, testObj) {

this.name = name;

this.testObj = testObj;

this.testObj.event1.subscribe(this.onEvent1, this);

}

3。响应函数

Consumer.prototype.onEvent1 = function(type, args, me) {

alert(” this: ” + this +

"n this.name: ” + this.name +

"n type: ” + type +

"n args[0].data: ” + args[0].data +

"n me.name: ” + me.name);

}

4。触发自定义事件

function TestData(data) {

this.data = data;

}

var t1 = new TestObj(mytestobj1);

var c1 = new Consumer(mytestconsumer1, t1);

var d1 = new TestData(mydata1);

t1.event1.fire(d1);

三、YUI(Dom Collection)

YUIdom工具包屏蔽了各种浏览器的差别,使用dom工具包可以方便的的操作页面元素,包括控制元素的坐标,以及改变元素的CSS风格。

     1Element的查找

YAHOO.util.Dom.get(element)

调用document.getElementById(element),获取指定的页面元素。

YAHOO.util.Dom.getElementsBy(method,tagName,rootNode)

rootNode的子节点中按照用户提供的method方法在所有标签为tagNameelement中查找符合条件的节点。rootNode不指定则在整个Document中查找,method是一个method(elementID)类型的函数对象,该函数对象的返回值为Boolean值。

YAHOO.util.Dom.getElementsByClassName(className, tagName, rootNode)

返回指定根节点下所有标签为tagName,classclassNameDOM节点数组。根节点为可选参数,不指定时在整个页面中查找

YAHOO.util.Dom.inDocument (el)

判断元素el是否在当前的DOM中,支持批量操作。

 2样式控制和访问

YAHOO.util.Dom.hasClass(element, className)

判断element标签上是否指明了classNameclass,支持批量操作

YAHOO.util.Dom.addClass(element, className)

给指定标签增加名为classNameclass,支持批量操作.

YAHOO.util.Dom.removeClass(element, className)

删除element上的名为classNameclass,支持批量操作

YAHOO.util.Dom.replaceClass(element, oldClassName, newClassName)

替换element上的oldClassName样式为newClassName,支持批量操作

YAHOO.util.Dom.getStyle(element, property)

获取elementstyle中的property属性,支持批量操作

YAHOO.util.Dom.setStyle(element,property,pValue)

设置elementstyleproperty属性为pValue,支持批量操作

注:本节中的class指的是CSS中定义的class

 3位置控制和访问

位置控制的相关函数

YAHOO.util.Dom.setX

YAHOO.util.Dom.setY

YAHOO.util.Dom.setXY

YAHOO.util.Dom.getX

YAHOO.util.Dom.getXY   返回元素坐标 [ left,top ]

YAHOO.util.Dom.getRegion

获取元素的坐标Region对象{left,top,right,bottom}

可支持批量操作

获取页面可视面积的高度和宽度

YAHOO.util.Dom.getClientWidth

YAHOO.util.Dom.getClientHeight

获取Document的高度和宽度

YAHOO.util.Dom.getDocumentWidth

YAHOO.util.Dom.getDocumentHeight

获取页面可视区域的高度和宽度(不包含滚动条)

YAHOO.util.Dom.getViewportHeight

YAHOO.util.Dom.getViewportWidth

Region对象:{left,top,right,bottom}

YUI提供的一个对象,用于完成多个矩形区域间的计算(如相交,包含。

YAHOO.util.Region.contains(region)

判断是否包含了region区域

YAHOO.util.Region.getArea

计算面积

YAHOO.util.Region.intersect(region)

计算与region区域的交迭区域

YAHOO.util.Region.union(region)

计算与region区域求并集(即包含两个区域的最小区域)

Point对象:{x,y}

YUI提供的对象,用于定义坐标点。

例:

获得和设置元素坐标

var pos = YAHOO.util.Dom.getXY(’test’);

YAHOO.util.Dom.setXY(’target’, pos);

设置元素的CSS属性

YAHOO.util.Dom.setStyle([test, test2], opacity, 0.5);

var opacity = YAHOO.util.Dom.getStyle(test2, opacity);

获得显示当前文档的窗口的大小。

var viewport = [

YAHOO.util.Dom.getViewportWidth(),

YAHOO.util.Dom.getViewportHeight()

];

获取和设置与CSS相关的属性

getElementByClassName(className,tagName,rootNode)

hasClass(element,className)

addClass(element,className)

removeClass(element,className)

replaceClass(element,oldClassName,newClassName)

YUI提供的CSS样式

Fonts    字体的规范样式,需要引入build/fonts/fonts-min.css 

 Rese     规范了所有HTML element的缺省样式,需要引入build/fonts/reset-min.css

Grids   提供了用于页面排版的CSS样式,需要引入build/fonts/grids-min.css

 五、YUI提供的element工具

YUI提供了一组操作页面element的工具,是对标准HTML elements的一种封装,能够直接通操作element的实例,使得增加监听器,操作DOM,设置/获取element的属性等工作变得很简单。部分方法是直接调用YUIDOM工具集提供的方法,如对class操作的相关方法、获取element的相关方法等等,在此不再重复。

YAHOO.util.Element(elementId)

创建element,如果elementIdDocument中还不存在,仍然可以通过YUI对他进行属性设置,增加监听器等操作, Element工具集会自动等到该elementId可用后执行这些操作,实际上真正的操作是等到contentReady事件发生后才进行的。

YAHOO.util.Element.appendChild(child)

DOM结构中element下增加子节点

YAHOO.util.Element.getElementsByTagName (tag)

获取tagNametag的所有页面元素

YAHOO.util.Element.hasChildNodes

判断是否具有子节点

YAHOO.util.Element.insertBefore (element, before)

在元素before前插入element

YAHOO.util.Element.removeChild(child)

删除DOM中元素的child子节点

YAHOO.util.Element.replaceChild (newNode , oldNode)

替换子节点oldNodenewNode

六、其它高级控件

1Button

对象定义:YAHOO.widget.Button

与传统HTML Form的按钮类似,不同的是它的label可以与 value不一致。还可以创建带菜单的按钮,或者radio buttoncheckbox

分类:

可以创建几种类型的按钮:

button:普通的下压式按钮,可以在按钮按下时执行用户指定的代码

link:按下时导航至相应的URL

submit:作用相当于form的提交按钮

reset:formreset按钮

checkbox:

radio:

menubutton:按下时显示隐藏按钮

splitbutton:按下时执行命令或显示菜单的按钮

使用Button必需的引入:

<!-- CSS -->

build/fonts/fonts-min.css

build/button/assets/button.css

<!-- Dependencies -->

build/yahoo-dom-event/yahoo-dom-event.js

build/element/element-beta-min.js

<!—使用menubuttonsplitbutton要用到的 -->

build/container/container_core-min.js

build/menu/menu-min.js

<!-- Source file -->

build/button/button-beta-min.js

初始化的方式:

1使用替换<input><span>的方式

constructorYAHOO.widget.Button(sourceElementId,{配置集})

Button的构造器首先根据sourceElementId DOM中查找<input>,一旦找到,就通过DOM replaceChild方法替换掉<input>

2使用新建的方式

constructor:YAHOO.widget.Button({配置集})

这种情况下根据配置集中指明的父id(Container)创建按钮,如果配置集中没有指明按钮则使用YAHOO.Dom.generateId生成buttonID,

Button的配置集

属性名称

含义

备注

id

替换后的新的element id

label

按钮上显示的文字

check

按钮选中/未选中的状态

checkbox用到

type

指明button的类型

缺省为button

container

按钮的父id

使用新建方式时会用到

srcelement

使用替换方式时

menu

按钮对应的菜单YAHOO.widget.menu

title

按钮title

没有指定label时使用title

href

按钮导航URL

仅在按钮类型为link时有效

target

<a>中的target

仅在按钮类型为link时有效

tabindex

tab切换焦点时的顺序号

onclick

click事件的响应函数

onclick:{
fn: Function, //
事件的响应函数.
obj: Object, // An object to pass back to the handler.
scope: Object // The object to use for the scope of the handler.
} }

2、              ButtonGroup

 

对象定义:YAHOO.widget.ButtonGroup

ButtonGroup是一组按钮,同组中只能有一个按钮被选中。根节点为<div>

3     AutoComplete

用户在文本输入框中输入文字时,该组件通过输入的内容查找符合输入条件的内容,并显示出所有符合条件的内容,供用户能够很快的完成正确的输入。

 AutoComplete的引入

<!-- 必须引入 -->

build/yahoo-dom-event/yahoo-dom-event.js

<!-- 可选: Connection(用到 XHR数据源时需要的引入) -->

build/connection/connection-min.js

<!--可选: 用到动画效果时需要的引入 -->

build/animation/animation-min.js

<!-- Source file -->

build/autocomplete/autocomplete-min.js

 控制AutoComplete的配置集

属性名称

含义

备注

animVert

控制下拉框向下展开的动画效果

animHoriz

控制下拉框水平方向展开的动画效果

animSpeed

控制动画的速度

delimChar

一行显示多条记录时的分隔符,可以是字符串数组或字符串

maxResultsDisplayed

结果集的最大显示行数

minQueryLength

进行查询前的输入的字符个数

queryDelay

用户键入字符后多少秒开始查询,默认0.5

autoHighlight

查询出来的结果集显示后,是否高亮显示第一条,默认为true

highlightClassName

高亮显示的样式名,默认为yui-ac-highlight

prehightlightClassName

鼠标移动到下拉框的一行上时,那一行的样式,默认为yui-ac-prehighlight

useShadow

下拉框是否有阴影

useIFrame

下拉框欠套在一个iframe中,用于解决IE中覆盖<select>的问题

forceSelection

限制输入内容必须为查询结果中的内容,如果不是则输入内容被删除

typeAhead

是否自动根据查询结果的第一条补齐到autocomplete

allowBrowserAutocomplete

是否允许浏览器提供的输入框记忆功能,默认为false

alwaysShowContainer

是否始终显示查询结果的下拉框,默认为false

AutoComplete的使用

1          自定义事件(CustomEvent)

AutoComplete除了默认的事件外,还有自定义的事件,以下为AutoComplete用到的各种CustomEvent

事件回调函数

含义

备注

textboxFocusEvent

输入框获得焦点的事件

textboxFocus

textboxKeyEvent 

按键弹起时的事件

textboxKey

dataRequestEvent

发出数据查询请求时的事件

dataRequest

dataReturnEvent

数据查询请求返回时的事件

dataReturn

dataErrorEvent

返回结果为空时的事件

dataError

containerExpandEvent

展开下拉框时的事件

containerExpand

typeAheadEvent

符合条件的结果自动用到第一条记录补齐时的事件

typeAhead

itemMouseOverEvent

鼠标移动到结果项上的事件

itemMouseOver

itemMouseOutEvent

鼠标移出结果项的事件

itemMouseOut

itemArrowToEvent

移动到某一选择项时的事件

itemArrowTo

itemArrowFromEvent

移出某一选择项时的事件

itemArrowFrom

itemSelectEvent

选中某一选择项的事件

itemSelect

unmatchedItemSelectEvent

forceSelectionfalse时,如果输入了不符合查询结果的内容时触发本事件。

unmatchedItemSelect

selectionEnforceEvent

强制从结果集中选择输入项时触发的事件

selectionEnforce

containerCollapseEvent

下拉框收缩时的事件

containerCollapse

textboxBlurEvent

输入框失去焦点时的事件

textboxBlur

可以根据需要重载自定义的事件

例:输入框获得焦点时自动进行查询,可以重载textboxFocusEvent

myAutoComp.textboxFocusEvent.subscribe(

      //发送一个查询条件为空的查询请求

function(){myAutoComp.sendQuery("");}

);

2          格式化下拉框的输出

如果返回的结果集中有多个属性,可以通过重载formatResult来格式化结果项的输出

oAutoComp.formatResult = function(oResultItem, sQuery) {

     var sMarkup = oResultItem[0] + " (" + oResultItem[1] + ")" ;

     return (sMarkup);

}

3          AutoComplete的数据源

l         DS_JSArray

data = ["AAA","BBB","BCC"];

var myDataSource = new YAHOO.widget.DS_JSArray(data);

可以通过DWR的方式调用java方法获得一字符串数组作为查询的下拉框,并在回调函数中可以直接使用,如:

l         DS_JSFunction

l         DS_XHR

对于JSArray方式取数时,AutoComplete可以自动根据输入的内容查在JSArray中查找符合条件的结果项,但在使用XHR方式时,YUI并没有提供默认的查找功能,必须由用户通过控制URL参数方式来实现这一功能。

JSON方式:

使用JSON格式时,创建数据源YAHOO.widget.DS_XHR时第一个参数为请求的URL,第二个参数为一数组,这一数组的第一条记录表示结果集在JSON对象的哪个对象属性下,如类似于下面结构的JSON对象

{

Result:{

data:[   {username:”Tom”,oldname:”Tom”,age:12”},

{username:”Jack”,oldname:”Jack”,age:16”}

]

}

}

如果是要查询username则结果集应该表示为”Result.data”

第二条记录为搜索的主键,同上面的例子中如果是要查找出符合条件的username,则第二个数组应为”username”,如果返回的结果集中还需要返回oldname属性,则应该指名数组的第三条记录”oldname”,后面还可以指定更多的需要返回的属性。

因此第二个数组对象参数可以用以下方法表示:

[结果对象,搜索的主键,额外的返回属性1,…额外的返回属性N]

function initAutocomplete(){

      var myDataSource1 = new YAHOO.widget.DS_XHR(

"./queryUsername.action",

["data","username"]);

      myDataSource1.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;

      //myDataSource1.scriptQueryAppend = "output=json&results=100";

      var oAutoComp = new YAHOO.widget.AutoComplete("user_username",

"usernameContainer", myDataSource1);

      oAutoComp.dataRequestEvent.subscribe(

function(oSelf,sQuery){

myDataSource1.scriptQueryParam = "username";

});

}

 XML方式:

应用方式与JSON方式类似,只是将reponseType指定为

myDataSource1.responseType = YAHOO.widget.DS_XHR.TYPE_XML

收集一下有关YUI的技术资料

英文:

Y! DN
学习YUI看这一个就够了,因为上面的资料和示例非常齐全,以至于很少有人再针对YUI写什么教程!

中文:

1. 台湾YDN
现在只是汉化了一小部分内容,不过至少有个像样点的中文站点

2.Yahoo! 使用者介面函示庫(YUI
台湾开发者写得一篇介绍YUI的好文

3. TW YUI@无名小站
暂时资料不多,好像是台湾 YUI blog

4. YAHOO工具库
一些YUI API文档的翻译

相对于YDN上的那些英文资料,感觉中文资料实在是太少了,甚至都没有一篇像样的简体中文资料!这让我没想到。以后我学习的时候尽量多写点学习笔记好了,虽然可能很简单,但于己可以加深印象,对和我一样的初学者可能也有点用

 

 

posted on 2009-04-21 11:15 重庆理工小子 阅读(10637) 评论(1)  编辑  收藏 所属分类: ajax编程

FeedBack:
# re: YUI中文文档
2009-04-21 21:07 | 与你同飞
很详尽,多谢分享。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: