国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
移動(dòng) web 應(yīng)用程序框架比拼,第 1 部分: 用 SproutCore 構(gòu)建移動(dòng)應(yīng)用程序

移動(dòng) web 應(yīng)用程序框架比拼,第 1 部分: 用 SproutCore 構(gòu)建移動(dòng)應(yīng)用程序

Michael Galpin, 軟件架構(gòu)師, eBay

簡介: Web 應(yīng)用程序發(fā)展迅速,移動(dòng) web 應(yīng)用程序的出現(xiàn)意味著再一次的飛躍。如今,人們期望 web 應(yīng)用程序提供一個(gè)本地體驗(yàn) — 一個(gè)和本地移動(dòng)應(yīng)用程序不差上下的移動(dòng) web 應(yīng)用程序。盡管移動(dòng) web 瀏覽器提供了使之成為可能的功能,但相比本地應(yīng)用程序開發(fā),web 開發(fā)仍然處于初級(jí)階段。SproutCore 是一個(gè) web 應(yīng)用程序框架,主要是為一個(gè)特定的設(shè)備開發(fā)類似于本地應(yīng)用程序的 web 應(yīng)用程序。探究 SproutCore 并將它作為一個(gè)構(gòu)建移動(dòng) web 應(yīng)用程序的框架來仔細(xì)研究。

本文的標(biāo)簽:  ajax, api, javascript, 應(yīng)用集成, 技巧, 集成

發(fā)布日期: 2011 年 10 月 17 日
級(jí)別: 中級(jí) 原創(chuàng)語言: 英文
訪問情況 : 2280 次瀏覽
評(píng)論: 1 (查看 | 添加評(píng)論 - 登錄)

平均分 (1個(gè)評(píng)分)
為本文評(píng)分

關(guān)于本系列

移動(dòng)應(yīng)用程序的開發(fā)發(fā)展迅速,許多開發(fā)人員選擇走移動(dòng) web 路線,不再為每個(gè)不同的移動(dòng)平臺(tái)重復(fù)編寫相同的應(yīng)用程序。然而,由于您 “追求 web”,您需要放棄本地移動(dòng)應(yīng)用程序開發(fā)人員曾經(jīng)和容易構(gòu)建的應(yīng)用程序框架。結(jié)果是出現(xiàn)了幾個(gè) web 應(yīng)用程序框架。在本系列的 4 篇文章中,我們將看到其中 4 個(gè)框架:SproutCore、Cappuccino、jQTouch 和 Sencha Touch。我們將對(duì)它們進(jìn)行比較,評(píng)估使用它們構(gòu)建一個(gè)移動(dòng) web 應(yīng)用程序的優(yōu)勢(shì)和劣勢(shì)。

先決條件

在本文中,我們將使用 SproutCore 框架創(chuàng)建一個(gè)簡單的移動(dòng) web 應(yīng)用程序。SproutCore 大量應(yīng)用 Ruby 和 Ruby Gems 生成代碼和構(gòu)建系統(tǒng)。本文使用 Ruby 1.8.7 和 Gems 1.3.7。SproutCore 是一個(gè)純 JavaScript 框架,沒有服務(wù)器端組件和較小的 HTML 和 CSS。任何 web 服務(wù)器都可以。從 參考資料 獲取這些工具的鏈接。

SproutCore 概述

您想要擴(kuò)展您的 iOS 設(shè)備的開發(fā)實(shí)現(xiàn)非 iOS 用戶嗎? 移動(dòng) web 和 SproutCore 的結(jié)合可能就是您所需的框架。SproutCore 為 web 帶來一個(gè)新的編程模型(靈感源于 Cocoa 框架)。

SproutCore 是 web 應(yīng)用程序的第一個(gè)也是最重要的一個(gè) Model-View-Controller (MVC) 框架。如果您是一個(gè) web 開發(fā)人員,那么您可能對(duì) MVC 框架,像 Struts 或 Ruby on Rails,比較熟悉。然而,SproutCore 不同于它們兩個(gè),因?yàn)樗鼈兪欠?wù)器端框架,而 SproutCore 是一個(gè)純客戶端框架,M、V 和 C 都是駐留在客戶端的。這實(shí)際上是 MVC 運(yùn)行一個(gè)更自然的方式;事實(shí)上,大多數(shù)桌面操作系統(tǒng)提供類似的 MVC 框架已經(jīng)十幾年了,因?yàn)檫@非常合適。

SproutCore 架構(gòu)不僅僅是一個(gè)簡單的 MVC 框架。它提供了一個(gè)綁定系統(tǒng),不再需要大量粘合代碼 來從模型獲取數(shù)據(jù)或者在應(yīng)用程序視圖中使用它。這類代碼在應(yīng)用程序控制層是很常見的,但是在一個(gè) SproutCore web 應(yīng)用程序中這完全不需要。它也提供一個(gè)抽象的頂端數(shù)據(jù)存儲(chǔ)和檢索。SproutCore 提供一些相對(duì)輕量級(jí)的小部件,它們?cè)谝苿?dòng)應(yīng)用程序中表現(xiàn)出色。SproutCore 的特性使得開發(fā)人員在一個(gè)較高級(jí)別的抽象上進(jìn)行編程,而不是在 web 應(yīng)用程序上;也不需要?jiǎng)?chuàng)建和訪問 HTML 元素、管理 CSS 樣式表或者使用 XMLHttpRequests 訪問遠(yuǎn)程服務(wù)器。相反,除了 JavaScript 之外,您還可以使用類似于桌面開發(fā)或者本地移動(dòng)應(yīng)用程序開發(fā)的編程模型進(jìn)行開發(fā)。

SproutCore 應(yīng)用程序內(nèi)部機(jī)制

一個(gè) SproutCore 應(yīng)用程序運(yùn)行時(shí)通常只由一個(gè) JavaScript 文件、一個(gè) CSS 文件和一個(gè) HTML 頁面組成。但是,它以大量 JavaScript 文件開始,這些文件被編譯成準(zhǔn)備部署到任何靜態(tài) web 服務(wù)器上的優(yōu)化文件。SproutCore 富有許多工具,包括構(gòu)建工具。要讓這些工具正常運(yùn)行,它們就必須清楚您的源代碼結(jié)構(gòu)。SproutCore 信賴慣例優(yōu)于配置( Convention over Configuration),包含生成項(xiàng)目結(jié)構(gòu)的工具和將要部署的具體文件,比如模型和控制器。這些工具是使用 Ruby 構(gòu)建的,功能非常類似于一些著名的 Ruby on Rails 框架工具。但是,SproutCore 是純粹的 JavaScript。在您的服務(wù)器上不需要 Ruby。您只需要將 Ruby 安裝在那些使用這些工具的開發(fā)機(jī)器上。

本文關(guān)注的是研究 SproutCore 應(yīng)用程序如何工作,而不是如何使用這些工具。因此,一個(gè)合適的 SproutCore 教程是很有幫助的。要研究 SproutCore 應(yīng)用程序,先來看一看您要使用 SproutCore 開發(fā)什么樣的移動(dòng) web 應(yīng)用程序。這個(gè)應(yīng)用程序應(yīng)該提供一個(gè)員工通訊錄,它應(yīng)該被設(shè)計(jì)為從移動(dòng)設(shè)備訪問。首先看看這個(gè)應(yīng)用程序,特別是它的數(shù)據(jù)訪問層。

數(shù)據(jù)、模型和存儲(chǔ)

SproutCore 開發(fā)通常采用一個(gè)自底向上的方法,從描述應(yīng)用程序所需的數(shù)據(jù)模型以及其如何從服務(wù)器訪問開始。因?yàn)?Javascript 對(duì)象沒有聲明類型的信息,正式聲明一個(gè)模型似乎有悖常理。但是,聲明一個(gè)模型的優(yōu)勢(shì)是顯而易見的。清單 1 展示了這個(gè)應(yīng)用程序的數(shù)據(jù)模型。


清單 1. 員工數(shù)據(jù)模型
				Intradir.Employee = SC.Record.extend({    firstName: SC.Record.attr(String, { isRequired: YES }),    lastName: SC.Record.attr(String, { isRequired: YES }),    phone: SC.Record.attr(String),    email: SC.Record.attr(String),    fullTime: SC.Record.attr(Boolean, { defaultValue: YES }),    fullName: function() {        return this.getEach('firstName', 'lastName').compact().join(' ');      }.property('firstName', 'lastName').cacheable()}) ;

清單 1 中的代碼顯示了員工數(shù)據(jù)模型的定義。該應(yīng)用程序稱為 Intradir,對(duì)象在應(yīng)用程序中有效。 SproutCore 模型稱為記錄,通常擴(kuò)展 SproutCore 類 SC.Record。聲明您記錄的屬性和類型。清單 1 有 5 個(gè)簡單屬性:firstName、lastName、phone、emailfullTime。前 4 個(gè)是字符串,最后一個(gè)是布爾值。要聲明這個(gè),使用 SC.Record.attr 幫助函數(shù)。這個(gè)幫助函數(shù)根據(jù)傳遞給它的類型(String、Boolean 和 Number)返回一個(gè) SC.RecordAttribute 實(shí)例。您必須向幫助函數(shù)傳遞類型。您也可以傳遞可選屬性。在清單 1 中,isRequired 選項(xiàng)觸發(fā) firstNamelastName 條件。fullTime 屬性有一個(gè)默認(rèn)值,被 defaultValue 選項(xiàng)觸發(fā)。

最后,注意您已經(jīng)聲明了一個(gè) fullName 屬性,也為它提供了一個(gè)函數(shù),這些計(jì)算屬性在 SproutCore 中是非常重要的。在本例中,函數(shù)檢索 firstNamelastName 屬性,并將它們放入一個(gè)類似數(shù)組的結(jié)構(gòu)中,然后使用連接函數(shù)將它們轉(zhuǎn)換成一個(gè)字符串。這就是函數(shù)聲明。在頂部,根據(jù) firstNamelastName 屬性聲明該計(jì)算屬性,且是可緩存的,這使得 SproutCore 在它第一次被計(jì)算之后緩存它的值,只要 firstNamelastName 值沒發(fā)生變化就可以使用緩存值。這種優(yōu)化為在移動(dòng)設(shè)備上的 SproutCore 性能作出了貢獻(xiàn)。

SproutCore 的 Record API 成為了輕量級(jí)對(duì)象關(guān)系映射(ORM)技術(shù)的基礎(chǔ)。如果您有多種彼此相關(guān)的記錄,您也可以定義一對(duì)多、多對(duì)一、和多對(duì)多的關(guān)系。要?jiǎng)?chuàng)建、存儲(chǔ)或檢索記錄,您需要 SproutCore 的 Datastore API。SproutCore 為您的應(yīng)用程序動(dòng)態(tài)創(chuàng)建一個(gè) Datastore。 需要做的就是為 Datastore 定義您的記錄和數(shù)據(jù)源,如 清單 2 所示。


清單 2. 員工數(shù)據(jù)源
				Intradir.EmployeesDataSource = SC.DataSource.extend({  // ..........................................................  // QUERY SUPPORT  //   fetch: function(store, query) {    if (query == Intradir.EMPLOYEE_QUERY_ALL){        SC.Request.getUrl('/app/employees.json')            .set('isJSON',YES)            .notify(this, this._didFetchAllEmployees, {                query: query,                store: store            }).send();        return YES;    }    return NO;  },  _didFetchAllEmployees: function(response, params){    if (SC.$ok(response)){        store.loadRecords(Intradir.Employee, response.get('body'));        store.dataSourceDidFetchQuery(query);    } else {        store.dataSourceDidErrorQuery(query, response);    }  },  // ..........................................................  // RECORD SUPPORT  //   retrieveRecord: function(store, storeKey) {    // Not supported    return NO ; // return YES if you handled the storeKey  },  createRecord: function(store, storeKey) {    // Not supported    return NO ; // return YES if you handled the storeKey  },  updateRecord: function(store, storeKey) {    // Not supported    return NO ; // return YES if you handled the storeKey  },  destroyRecord: function(store, storeKey) {    // Not supported    return NO ; // return YES if you handled the storeKey  }}) ;

創(chuàng)建一個(gè)數(shù)據(jù)源最簡單的方法是使用 SproutCore 代碼生成工具。它為您提供一個(gè)對(duì)象,擴(kuò)展 SC.DataSource 并為您提供 5 個(gè)函數(shù)來實(shí)現(xiàn):fetch、retrieveRecord、createRecord、updateRecorddestroyRecord。在清單 2 的示例中,fetch 函數(shù)已經(jīng)實(shí)現(xiàn),無論執(zhí)行任何查詢,它都被調(diào)用;fetch 函數(shù)尋找一個(gè)特定查詢。清單 3 顯示該查詢以及使用方法。


清單 3. Example of a SproutCore 查詢示例
				// Declare this in core.js so it can be used anywhere Intradir.EMPLOYEE_QUERY_ALL = SC.Query.local(Intradir.Employee);Intradir = SC.Application.create({      NAMESPACE: 'Intradir',      VERSION: '0.1.0',   // Create the store, and point it at our datasource   store: SC.Store.create().from('Intradir.EmployeesDataSource') }) ;// Now in your application you can use the queryvar directory = Intradir.find(Intradir.EMPLOYEE_QUERY_ALL);

清單 3 中的樣例代碼顯示的示例是 SproutCore 支持的查詢中最簡單一個(gè)。像這樣的一個(gè)本地查詢僅僅針對(duì) Datastore 中本地存儲(chǔ)的內(nèi)容進(jìn)行查詢。然而,清單 2 顯示的是 Datastore 從服務(wù)器加載的數(shù)據(jù)。為此,使用 SproutCore 中的 Ajax 實(shí)用工具。該調(diào)用是異步的,因?yàn)楹笈_(tái)使用的是 XMLHttpRequest。因此,當(dāng)數(shù)據(jù)從 服務(wù)器返回時(shí),回調(diào)函數(shù) _didFetchAllEmployees 被調(diào)用。您可以以任何形式調(diào)用此函數(shù),但是必須遵守 SproutCore 的命名約定。帶一個(gè)下劃線前綴的函數(shù)表示它是私有的,使用 Cocoa 樣式命名(didDoWhateverWeSaidWouldDo)。

如果您想支持其他查詢,向 fetch 函數(shù)添加任何您需要的邏輯。這可以包含遠(yuǎn)程查詢,其中查詢結(jié)果直接從服務(wù)器得到,這通常涉及到自動(dòng)形成一個(gè) URL 來從服務(wù)器查詢,通常通過添加回調(diào)函數(shù)來生成結(jié)果。類似地,SproutCore 數(shù)據(jù)源 API 支持對(duì)單個(gè)記錄進(jìn)行操作,盡管這在本例中不能實(shí)現(xiàn)。這通常取決于您后臺(tái)的構(gòu)架方式。對(duì)于這些在應(yīng)用程序中的數(shù)據(jù),您只需要顯示它以及與它交互。在您進(jìn)行這些操作之前,創(chuàng)建一個(gè)可以填入數(shù)據(jù)的用戶界面。

JavaScript 視圖、控制器和鍵值 observer

SproutCore 中的視圖代碼是用 JavaScript 寫的,且使用一個(gè)聲明式樣式編寫的,在很多方面和 HTML 相似。主要差別是 SproutCore 提供高級(jí)別的組件,您只需要將您的數(shù)據(jù)插入并連接到事件監(jiān)聽程序(通常稱為 “observer”)。對(duì)于這個(gè)應(yīng)用程序,加載一個(gè)簡單的含有員工信息的表;該表支持在其任何列上分類。清單 4 顯示了視圖代碼。


清單 4. 創(chuàng)建一個(gè)表視圖
				Intradir.nameColumn = SC.TableColumn.create({     key: 'fullName',     label: 'Name',     width: 50 });Intradir.emailColumn = SC.TableColumn.create({     key: 'email',     label: 'Email',     width: 50 });Intradir.phoneColumn =  SC.TableColumn.create({    key: 'phone',    label: 'Phone',    width: 50});Intradir.mainPage = SC.Page.design({    mainPane: SC.MainPane.design({        childViews: 'tableView'.w(),        tableView: SC.TableView.design({            layout: { left: 15, right: 15, top: 15, bottom: 15 },            backgroundColor: "white",             columns: [                 Intradir.nameColumn,                 Intradir.emailColumn,                 Intradir.phoneColumn            ],            contentBinding:   'Intradir.directoryController.arrangedObjects',            selectionBinding: 'Intradir.directoryController.selection',            selectOnMouseDown: YES,                   exampleView: SC.TableRowView,                    recordType: Intradir.Employee,            nameColumn: Intradir.nameColumn,            emailColumn: Intradir.emailColumn,            phoneColumn: Intradir.phoneColumn        })    })});

這段代碼在 /resources/main_page.js 文件中可以找到。將這當(dāng)作 JSON 數(shù)據(jù),即使您也可以調(diào)用代碼。減少視圖腳本中使用的命令代碼,注意綁定已經(jīng)在創(chuàng)建的表和數(shù)據(jù)結(jié)構(gòu)(是 directoryController 的一部分)之間聲明了。返回此頁的是控制器。清單 5 顯示的是它的代碼。


清單 5. 主頁面的控制器
				Intradir.directoryController = SC.ArrayController.create({    // nothing to see here!}) ;

清單 5 中顯示的這個(gè)控制器是非常簡單的。最重要的是它是一個(gè)數(shù)組控制器,這意味著它擴(kuò)展了 SC.ArrayController。如果您返回到清單 4 中的綁定聲明,引用的屬性是 arrangedObjectsselection,在 SC.ArrayController 中定義的。這是一個(gè)常用的控制器,顧名思義,它有一個(gè)存儲(chǔ)視圖所需的模型數(shù)據(jù)的數(shù)組。這一過程所需的應(yīng)用程序安裝代碼如 清單 6 所示。


清單 6. 應(yīng)用程序安裝代碼
				Intradir.main = function main() {     Intradir.getPath('mainPage.mainPane').append();    var directory = Intradir.find(Intradir.EMPLOYEE_QUERY_ALL);    var dirController = Intradir.directoryController;    dirController.set('content', directory);    var tableView = Intradir.getPath('mainPage.mainPane.tableView');        // helper function    function handleSort(key, column){        var content = controller.get('content').sortProperty(key);        if (column.get('sortState') === SC.SORT_DESCENDING){            content = content.reverse();        }        dirController.set('content', content);        tableView.set('content',content);        tableView.displayDidChange();        tableView.awake();    }        // add observers    tableView.nameColumn.addObserver('sortState', function(){        handleSort("fullName", tableView.nameColumn);    });    tableView.emailColumn.addObserver('sortState', function(){        handleSort("email", tableView.emailColumn);    });    tableView.phoneColumn.addObserver('sortState', function(){        handleSort("phone", tableView.phoneColumn);    });     };function main() { Intradir.main(); }

使用 Datastore 中的數(shù)據(jù)填充控制器,這樣控制器就有一個(gè)返回它的數(shù)組。如果您的目標(biāo)只是顯示表格,那就可以了,因?yàn)橛嘞碌拇a可以完成分類。如果不是,定義一個(gè)幫助函數(shù),您可以用來在表的每一列上進(jìn)行分類。最后,分別向 3 列添加 observer。每個(gè) observer 尋找一個(gè) sortState 事件,然后使用幫助函數(shù)來對(duì)數(shù)據(jù)進(jìn)行分類并刷新 UI。這種事件處理風(fēng)格被稱為 Key-Value Observing(KVO)。Cocoa 框架大量使用此范例;它被 SproutCore 引入 JavaScript 和 web 開發(fā)領(lǐng)域。

SproutCore 和移動(dòng)開發(fā)

SproutCore 網(wǎng)站提出這樣一個(gè)問題,“我們?nèi)绾螛?gòu)建極其快速的桌面級(jí)(desktop-class)web 應(yīng)用程序?”,并指出答案就是 SproutCore。 但是這個(gè)問題并沒有提及移動(dòng) web 應(yīng)用程序,只是強(qiáng)調(diào)了桌面級(jí) web 應(yīng)用程序。這是否意味著 SproutCore 是唯一一個(gè)只能從桌面 web 瀏覽器訪問的 web 應(yīng)用程序?要正確回答這一問題,考慮 Hedwig, 使用 SproutCore 的一個(gè)示例,專為觸控設(shè)備設(shè)計(jì)的 web 應(yīng)用程序。

Hedwig 示例向您既展示了移動(dòng)應(yīng)用程序使用 SproutCore 的好的一面,也展示了不好的一面。最好能在一個(gè)大尺寸觸摸屏設(shè)備(比如 iPad)上看看。SproutCore 可以協(xié)助許多移動(dòng)設(shè)備的基礎(chǔ)開發(fā),比如,處理觸摸事件、方向變換和動(dòng)態(tài)大小控制。如果您在一個(gè)較小的屏幕(iPhone 或者 Android 手機(jī))上觀察,那您將會(huì)注意到一些功能不能正常運(yùn)行。 圖 1 顯示了 Hedwig 在 iPad 和在 iPhone 上的效果。


圖 1. Hedwig 在 iPad 和在 iPhone 上的效果

這里的問題主要是一個(gè)布局功能;頁面是專為大屏幕設(shè)計(jì)的,并針對(duì)移動(dòng)設(shè)備適當(dāng)?shù)匕才乓恍┢聊煌獾目刂?。更進(jìn)一步地說,它使用一個(gè)移動(dòng)良好的特性 — 視窗,使頁面可伸縮。這意味著當(dāng)控件離開移動(dòng)屏幕時(shí),您不能縮小來訪問控件。然而,為小觸摸屏制作這樣一個(gè)良好的頁面只是舉手之勞。

考慮使用 SproutCore 進(jìn)行移動(dòng)開發(fā)時(shí),記住,目前它的許多 UI 組件并不是為小屏幕設(shè)計(jì)的。這些組件的大小或布局對(duì)于這些移動(dòng)視頻可能不是最好的??紤]組件的大?。ň褪钦f,需要多少 JavaScript 和 CSS)以及 CPU 和內(nèi)存的密集程度。幸運(yùn)的是,就顯示速度而言,SproutCore 是最優(yōu)的,因此移動(dòng)設(shè)備中較慢的處理器不會(huì)對(duì)您造成太大的麻煩。但,使用更大、更復(fù)雜的組件(比如,示例中所用的 SC.TableView )時(shí)一定要格外小心。記住 SproutCore 含有幫助方法可以創(chuàng)建原始 HTML ,可通過一個(gè)定制的組件顯示。

結(jié)束語

這篇介紹 SproutCore 的文章著重強(qiáng)調(diào)它的框架,以及如何使用它開發(fā)移動(dòng) web 應(yīng)用程序。一方面,SproutCore 提供了一個(gè)豐富的客戶端 MVC 框架,用來創(chuàng)建利用 JavaScript 作為編程語言的 web 應(yīng)用程序。它使用綁定極大地減少了樣板文件代碼。它還提供了 Ajax 頂層抽象,并鼓勵(lì)在客戶端構(gòu)建所有的 UI,進(jìn)到服務(wù)器上訪問數(shù)據(jù)。該構(gòu)架對(duì)于使用 HTML5 技術(shù)(比如,應(yīng)用程序緩存)的移動(dòng) web 應(yīng)用程序是完美的。SproutCore 還包括對(duì)觸摸事件的抽象,這可能導(dǎo)致在移動(dòng)設(shè)備上的 UI 更為密集。另一方面,SproutCore 對(duì)于移動(dòng)設(shè)備而言并不是最優(yōu)的,并不是它的所有 UI 組件都適合移動(dòng)設(shè)備,因此,您可能需要構(gòu)建一些在智能手機(jī)上能運(yùn)行得更好的定制 UI 組件。


下載

描述名字大小下載方法
Intradir 樣例代碼intradir.zip7KBHTTP

關(guān)于下載方法的信息


參考資料

學(xué)習(xí)

獲得產(chǎn)品和技術(shù)

討論

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
跨越邊界: Streamlined,第 1 部分
跨平臺(tái)移動(dòng)應(yīng)用程序開發(fā)框架列表
那些程序員用過都說好的HTML5框架,響應(yīng)式網(wǎng)站開發(fā)很輕松
Groovy和Grails簡介
主流跨平臺(tái)移動(dòng)應(yīng)用開發(fā)框架比較
EasyTime - Ruby學(xué)習(xí)筆記 | Agile Web Development with Rails 翻譯(一)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服