日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

积木Sketch Plugin:设计同学的贴心搭档

發布時間:2023/12/20 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 积木Sketch Plugin:设计同学的贴心搭档 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

多年來,美團外賣一直在高速增長,但整個客戶端的UI組件一直沒有得到很好的統一。而在開發過程中因UI缺乏同一的標準導致各種問題凸顯,積木插件Sketch Plugin應運而生。外賣技術團隊將其打造成為UI一致性的抓手,最終幫助團隊減少開發成本,提升了交付的質量,并為美團多個業務團隊提供了很好的支持服務。

本文主要介紹了Sketch Plugin項目的背景,并由淺入深地帶領大家認識了Sketch Plugin項目,文中還詳細解讀了該技術的各種優缺點,同時還提供了詳細的實踐步驟和踩坑總結。希望本文對大家打造一致性體驗能夠有所幫助。

|?A?consistent experience is a better experience.——Mark Eberman

|?一致的體驗是更好的體驗。——Mark Eberman,知名設計師

背景

1. UI一致性項目

積木(Tangram)Sketch插件源于美團外賣UI的一致性項目,該項目自2019年5月份被提出,是UI設計團隊與研發團隊共建的項目,目的是改善用戶端體驗的一致性,提升多技術方案間組件的通用性和復用率,整體降低視覺改版的研發成本。

一直以來,外賣業務都處于高速發展階段,人員規模在不斷擴大,項目復雜度在持續增加。目前平臺承載了美團餐飲、商超、閃購、跑腿、藥品等多個業務品類,用戶入口也覆蓋了美團App外賣頻道、外賣App、大眾點評等多個獨立應用。因為客戶端一直比較側重業務開發,為了滿足業務快速上線的需求,UI組件并沒有統一的實現,而是分散到各個業務場景中,在開發過程中因UI缺乏同一的標準而導致以下問題不斷凸顯:

UI/UE層面

① UI缺乏標準化的設計規范,在不同App及不同語言平臺上設計風格不統一,用戶體驗不一致。

② 設計資源與代碼均缺乏統一的管理手段,無法實現積累沉淀,無法適應新業務的開發需求。

RD層面

① 組件代碼實現碎片化,存在多次開發的情況,質量難以得到保證。

② 各端代碼API不統一,維護拓展成本較高,變更主題、適配Dark Mode等需求難以實現。

QA層面

重復走查,頻繁回歸,每次發版均需驗證組件質量。

PM層面

版本迭代效率低,版本需求吞吐量低,不能滿足業務的快速拓展能力。

基于上述開發工作中的切實痛點,以及未來可預見的對客戶端能力的開發需求,我們迫切需要一套統一的UI設計規范,以此沉淀出設計風格,建立統一的UI設計標準,從而抽離成熟的業務場景,提供高質量、可擴展、可統一配置的同時能基于Android/iOS/MRN/Mach組件開發的代碼庫,且具備支持多業務高層次的代碼復用能力,提高UI業務的中臺能力,使項目具有高度一致性。

我們通過積木Sketch插件來落地設計規范,可以保證設計元素均從既定設計標準中獲取,產出符合業務設計語言的設計稿,而各平臺UI組件庫中也有對應實現,從而使積木插件成為UI一致性的抓手,最終可以減少開發成本,提升交付質量,服務好我們美團的多個業務團隊。

外賣UI一致性項目

2. Sketch & Sketch Plugin

要想保持UI一致性,就不能打破規則。從設計階段顏色的選擇、字體的規范、控件的樣式到RD開發階段代碼的統一管理、API的制定、多端的實現方式,都必須遵守一套規則,而Sketch Plugin建設則是讓規范落地執行的解決方案。

在討論其重要性之前,我們首先簡單介紹一下Sketch:Sketch是一個設計工具包,由總部位于荷蘭海牙的BohemianCoding團隊開發,該團隊成員目前不足百人,來自全球多個國家,通過互聯網遠程協作開發,屬于典型的高效開發團隊。

Sketch容易理解且上手簡單;可與團隊中的每個人創建、更新和共享所有Symbol組件,實現設計資源的共享和版本管理,從此告別“final-final-final-1”;其版本迭代速度非常快,且能不斷添加新功能,滿足用戶的需求,更符合互聯網時代;Sketch可以使用真實數據進行設計。目前,我們設計團隊已經全面使用Sketch進行設計。

設計語言包括Iconfont、色板、文字規范、話術、插畫、動畫、組件等。其實它并不是一個抽象的概念,比如大家提到“美團”就會想起“美團黃”,想到可愛的“袋鼠”,想到那些騎著摩托車、穿著印有“美團外賣”亮黃色衣服的騎手小哥。通過設計語言,我們可以更好地傳達品牌主張和設計理念。UI團隊逐步將設計語言沉淀為設計規范,并將其量化內置于積木Sketch Plugin中,使產出的設計稿和RD代碼庫中的組件一一對應,從而形成一個完整的閉環,進而可加速整個業務的交付流程。

使用Sketch Plugin可以快速設計出標準頁面

積木Sketch Plugin功能演示

3. 積木Sketch 插件項目

其實,市面上已存在類似插件,為什么我們還要自己動手開發呢?因為UI設計語言與自身業務關聯性很強,不同業務的色彩系統、圖形、柵格系統、投影系統、圖文關系千差萬別,其中任意一環的缺失都會導致一致性被破壞。現有插件所提供的通用設計元素無法滿足外賣設計團隊的需求,開發一款可以與業務強關聯且功能可定制的插件,顯得尤為重要。

此外,統一的品牌符號、品牌特征,也有助于加深產品在用戶心中的印象,統一的顏色和交互形式能幫助用戶加深對產品的熟悉感和信任感,一個好的設計語言本身可以在體驗上為產品加分,也能夠更好創造一致性的體驗。

積木Sketch插件經過一段時間的建設,目前已具備Iconfont、標準色板、組件庫、數據填充、文字模板等功能。

我們通過Iconfont可以從美團的圖標庫中拉取設計團隊上傳的SVG圖標,并直接應用于設計稿;標準色板可以限定設計師的顏色使用范圍,確保設計稿中的顏色均符合設計規范;組件庫中包含從外賣業務中抽離的基本控件與通用組件,具有可復用和標準化的特點,并與不同語言平臺組件庫中的代碼一一對應,使用組件庫中的組件進行設計,可以提升UI的設計效率、開發效率以及走查效率;數據填充庫可以實現圖片填充和文本填充,圖片包含了商品及商家素材,文字則包含了菜品、商鋪名等信息,通過數據填充可以使設計師采用真實數據進行填充,讓設計稿更為直觀,也更貼近線上環境;文字模板中內置了Head、SubTitle、Body、Caption的使用規范,根據設計稿中文字的位置,點擊文字圖層即可直接應用字體、行高、字距等屬性。

此外,我們還根據設計同學的使用反饋,不斷增添新功能。同時也在拓展插件的使用場景,增加業務線切換功能,使積木插件可以為更多的團隊服務,并期待它能成為更多設計師的“貼心搭檔”。

積木Sketch Plugin已支持功能

4. 為什么要寫這篇文章?

相信你讀完上面的內容,肯定迫不及待的想了解一下Sketch插件,以此迅速提升自己團隊開發效率了吧?

其實在開始之前,我們可先了解一些不利的條件。第一點,由于Sketch更新速度極快,但是官方文檔卻十分簡單且陳舊,因此很多知名的Sketch Plugin因每次API的變更過大紛紛放棄維護;第二點,由于開發技術棧混亂,成熟項目一般還未開源,而開源的項目基本上沒有什么參考價值,絕大多數都是“update 3 years ago”;最后一點,macOS開發資料更是少的可憐。

我們閱讀了大量的文檔卻沒有理清頭緒,仿佛很多Wiki講到關鍵地方,比如某個非常期待的功能是怎么實現的時候,作者竟然一筆帶過,讓人摸不到頭腦。知乎上一篇Sketch Plugin的科普文,很多網友會評論“求教學視頻,我可以花錢買的”。經過一步步踩坑,我們就總結了一些開發經驗,為了避免大家“重復踩坑”,晚上可以早點下班陪陪家人,我們決定寫一篇文章記錄下開發的過程。雖然比起那些已經更新多版的成熟項目,但還有不少的差距,至少可以讓大家不再那么迷茫。

當然,即使你覺得自己是個“跟Sketch八竿子打不著”的開發同學,我們也覺得這篇文章同樣也值得閱讀,因為你會通過本文接觸到前端、移動端、桌面端、服務端的各種開發知識。我們都知道,越來越多的公司開始喜歡招全棧工程師,像Facebook基本上只招全棧工程師。你心里是不是在想:“是不是在搞笑啊?不過一個插件而已?”先別輕易下結論。

準備好了嗎?盤它!

準備放手Coding之前

好,先別著急敲擊鍵盤。畢竟我們連使用哪種語言去開發都沒決定,這曾經也是困惱我們許久的一個問題。目前Sketch Plugin開發大概有兩種方式:

① 使用JavaScript + CocoaScript的混合開發模式,Sketch團隊官方維護了一套JS API,并在開發者官網寫了一句非常振奮人心的話:“ Take advantage of ES6, access macOS frameworks and use the Sketch APIs without learning Objective-C or Swift.”

理想很美滿,但現實很骨感。這個API目前還不算完善,很多功能無法實現,因此我們需要搭配CocoaScript訪問更豐富的內部API。

② 直接采用Objective-C 或Swift,并搭配macOS的UI框架AppKit進行開發,簡單粗暴,并且可以利用OC運行時直接調用Sketch內部API。但這里要特別提醒一下,你要承擔的風險是:隨著Sketch的不斷更新,內部API的命名和使用方式可能會發生較大變化,很多知名插件都因此放棄更新

本文采用了“混合開發模式”進行講解,希望能夠給你一些小啟發。

Sketch 開發原理

1. Sketch Plugin開發流派

2. 環境配置

Skpm(Sketch Plugin Manager)是Sketch提供的用于Plugin創建、Build以及發布的官方工具。Skpm采用Webpack作為打包工具,當然如果你對前端知識足夠熟悉,也可以采用Rollup或者roadhog。但是,為了防止遇到各種各樣的報錯,這里并不建議你這么做。

Skpm提供了一系列幫助快速入門的模板,最有用的莫過于skpm/with-webview,它可以幫助我們創建一個基于WebView展示的Demo示例,而且Skpm會在構建完成后,自動創建一個Symbolic Link將插件添加到Sketch的安裝目錄,使Plugin立即可用。

//基于webpack的Sketch官方打包工具skpm npm?install?-g?skpm //創建示例工程 skpm?create?my-plugin?--template=skpm/with-webview //Install?the?dependencies npm?install //構建插件 npm?run?build

3. 項目結構

Plugin Bundle

按照上面的步驟操作完成后,我們會得到如下插件目錄,它以標準化的分層結構存儲了源碼文件以及構建生成的Sketch插件安裝包。這里沒有使用官方文檔中最簡單的Demo,而是使用目前開發中最為常用的With-Webview模板進行分析,以免出現學完“1+1”后遇到的全是“微積分”問題,并且大部分插件均是在此基礎上進行拓展。

目錄中的參數,相信你在看完注釋后馬上就能明白。可是如果此前沒有前端開發經驗,可能不了解在經過Webpack打包后,腳本文件的文件名會發生變更,比如resources中的webview.js經過打包后會儲存在插件的Resources文件夾中,而文件名則變更為resources_webview.js,因此在進行代碼編寫時,如果需要在html中引用此文件,也要使用打包后的文件名,即:<script src="../resources_webview.js"></script>。這里有個小技巧,如果你不知道腳本文件打包后的文件名及路徑,建議先使用Webpack進行編譯,然后查看其在打包后的Plugin中的位置和名稱,然后再進行引用。

├──?assets?//資源文件夾,如需更改需在package.json中的skpm.assets中設置? ├──?my-plugin.sketchplugin???//skpm構建過程生成的插件包 │???└──?Contents │???????├──?Resources │???????│???└──?_webpack_resources │???????│???└──?resources_webview.js │???????│???└──?resources_webview.js.map │???????└──?Sketch │???????????├──?manifest.json │???????????├──?__my-command.js │???????????└──?__my-command.js.map ├──?package.json ├──?webpack.skpm.config.js ├──?resources?//資源文件 │??├──?style.css │??├──?webview.html │??└──?webview.js └──?src?//需要被webpack打包的腳本文件以及manifest清單文件├──?manifest.json└──?my-command.js

Manifest

你沒有看錯!plugin中也有manifest.json,它與其它平臺比如Android開發中的清單文件意義相同。清單文件記錄了作者信息、描述、圖標以及獲取更新的途徑等等。想想看,每天熬夜加班寫代碼,總得有個地方把你的名字記錄下來吧。但manifest最重要的作用其實是告訴Sketch如何運行插件,以及如何將插件集成進Sketch的菜單欄中。

commands使用一個數組,記錄了插件所提供的所有命令。比如下面的例子,當用戶從菜單欄點擊 “顯示工具欄”這個條目時,就會執行script.js中的function showPlugin() 。menu則提供了插件在Sketch菜單欄中的布局信息,Sketch會在插件被加載時初始化菜單。

{"commands":?[{"name":?"顯示工具欄","identifier":?"roo-sketch-plugin.toolbar","script":?"./script.js","handlers":?{"run":?"showPlugin"}}],"menu":?{"title":?"????外賣積木SketchPlugin工具欄","items":?["roo-sketch-plugin.toolbar"]} }

package.json

簡單來說,只要你的項目中用到了NPM,根目錄下就會自動生成package.json文件。Node.js項目遵循模塊化的架構,package.json定義了這個項目所需要的各種模塊以及配置信息。使用npm install命令會根據這個配置文件,自動下載所需的模塊,也就是配置項目所需的運行和開發環境。

非常值得稱贊的是,Plugin開發中對于網絡請求、 I/O 操作以及其它功能,可以使用與Node.js兼容的polyfill,其中許多常用modules已經預裝到了Sketch中,比如console、fetch、process、querystring、stream、util等。

這里你只需要知道以下幾點:

  • 需要參與Webpack打包的腳本文件必須在resources目錄下聲明,否則不會參與編譯(重點!考試要考!)。

  • assets目錄需要配置在skpm.assets下。

  • 常用的命令可以定義在scripts中方便直接調用。

  • dependencies字段指定了項目運行所依賴的模塊,devDependencies指定項目開發所需要的模塊。

{"name":?"roo-sketch-plugin","author":?"hanyang","description":?"外賣積木Sketch?plugin,UI同學好喜歡~","version":?"0.1.0","skpm":?{"manifest":?"src/manifest.json","main":?"roo-sketch-plugin.sketchplugin","assets":?["assets/**/*"]},"resources":?["src/webview/template/webview.js"],"scripts":?{"build":?"rm?-rf?roo-sketch-plugin.sketchplugin?&&?NODE_ENV=development?skpm-build",},"dependencies":?{},"devDependencies":?{} }

4. API Reference

JavaScript API

由于使用了與Safari相同的JS引擎,Plugin腳本可以獲得完整ES6支持。官方的JavaScript API由Sketch團隊維護,并允許訪問和修改Sketch文檔,通過API可以向Sketch用戶提供數據并提供一些基本的用戶界面集成。

//訪問、修改和創建文檔從color到layer再到symbol等方方面面 var?sketchDom?=?require('sketch/dom') //對于異步操作,JavaScript?API提供了fibers延長contex的lifeTime var?async?=?require('sketch/async') //直接在Sketch中提供圖像或文本數據,DataSupplier直接與Sketch用戶界面集成。 var?DataSupplier?=?require('sketch/data-supplier') //無需重新build的情況下顯示通知以及獲取用戶輸入 var?UI?=?require('sketch/ui') //保存圖層或文檔的自定義數據,并存儲插件的用戶設置。 var?Settings?=?require('sketch/settings')

CocoaScript Syntax

CocoaScript通過賦予了JavaScript調用Sketch內部API以及macOS Cocoa frameworks的能力,這意味著除了標準的JavaScript庫外,還可以使用許多很棒的類與函數。CocoaScript建立在蘋果的JavaScriptCore之上,而JavaScriptCore是為Safari提供支持的JavaScript引擎。

因此,當你使用CocoaScript編寫代碼的時候,你就是在寫JavaScript。CocoaScript中的Mocha實現JS到Objective-C的Bridge,雖然Mocha包含在CocoaScript中,但文檔仍保留在原始Github中。因此,你在CocoaScript的Readme中看不到任何語法教程。這里一個訣竅是,如果你想了解Mocha將原生的Sketch Objects通過bridge,從Objective-C傳遞到JavaScript層的屬性、類或者實例方法的信息,可以將其通過console打印出來:

let?mocha?=?context.document.class().mocha() console.log(mocha.properties()) //OC [executeOperation:withObject:error:] //CocoaScript executeOperation_withObject_error()

通過CocoaScript 提供的Bridge使用JavaScript調用Objective-C的基本語法如下:

  • Objective-C的方括號語法“[ ?]”轉換為JavaScript中的點“ . ”語法。

  • Objective-C的屬性導出到JavaScript時Getter為object.name() ?而Setter為object.name = 'Sketch'。

  • Objective-C的selectors被暴露為JavaScript 的代理方法。

  • “:” 冒號被轉換為下劃線“ _”, 最后一個下劃線是可選的。

  • 調用帶有一個下劃線的方法需要加倍為兩個下劃線: sketch_method變為sketch__method。

  • selector的每個component被連接成不帶有分隔符的單個字符串。

5. Actions

行為定義

Action指的是由于用戶交互而在應用程序中發生的事件,比如“打開文檔”、“關閉文檔”、“保存”等。Sketch所提供的了Action API可以使插件對應用程序中的事件做出反應,有點類似Android開發中的的BroadCast或者Job Scheduler。官方文檔列舉了數百個可供監聽的Action,但最常用到的只有下面幾個:

監聽回調

我們只需在插件的manifest.json文件中添加一個handler即可。比如下面的例子添加了對于“OpenDocument”的監聽,也就是告訴插件在新文檔被打開時要去執行onOpenDocument這個function。

?{"script":?"action.js","identifier":?"my-action-listener-identifier","handlers":?{"actions":?{"OpenDocument":?"onOpenDocument"}} }

當一個Action被觸發時,會回調JS中的監聽方法,與此同時Sketch可以向目標函數發送Action Context,其中包含動作本身的一些信息。在下面例子中,每次打開文檔時都會彈出一個Toast。

function?onOpenDocument(context)?{context.actionContext.document.showMessage('Document?Opened') }

6. Bridge雙向通信

在常規的插件開發中,UI層一般采用Webview實現,因此你可以使用各種前端開發框架,比如React或者Vue等;而插件的邏輯層(負責調用Skecth API)顯然不在WebView中,因此需要通過Bridge進行通信。邏輯層將從服務器獲取到的數據傳遞給UI層展示,而UI層則將用戶的操作反饋傳遞給邏輯層,使其調用Sketch API更新Layers。

Sketch 通信原理

插件發送消息到WebView

//On?the?plugin: browserWindow.webContents.executeJavaScript('someGlobalFunctionDefinedInTheWebview("hello")').then(res?=>?{//?do?something?with?the?result})//On?the?WebView: window.someGlobalFunctionDefinedInTheWebview?=?function(arg)?{console.log(arg) }

WebView發送消息給插件

//On?the?webview: window.postMessage('nativeLog',?'Called?from?the?webview') //On?the?plugin: var?sketch?=?require('sketch') browserWindow.webContents.on('nativeLog',?function(s)?{sketch.UI.message(s) })

經過了以上步驟,我們就得到了一個基礎插件,它以WebView作為內容載體,并具有雙向通信功能。打開插件時,Webview會將頁面加載完成的事件傳遞給邏輯層,邏輯層調用Sketch API彈出Toast;點擊Get a random number可以從邏輯層獲取一個隨機數。

skpm/with-webview 運行效果

快來正式加入開發隊伍

相信閱讀完上面的部分,制作一個簡單的插件對于你來說,已經有點“游刃有余”了。但這個時候,疑惑也隨之而來,為什么Demo和我們常用插件的UI差別如此之大?

沒錯,官方文檔只教給我們最基礎的插件開發流程,一個成熟的商業項目絕不僅僅是以上這些。一個功能完善的插件應該包括以下三部分:工具欄、WebView容器以及業務數據。下面,我們會一步步為你展示如何開發一個商業化插件UI,同時也會演示美團外賣“填充功能”的實現(注:篇幅原因文檔中僅保留關鍵代碼。)

常規Sketch插件結構

1. 創建吸附工具欄

所謂吸附式工具欄,就是展示在Skecth右側Inspector Panel旁邊的工具欄,它以吸附的方式與Sketch操作界面融為一體,這也是絕大多數插件的視覺呈現方式。工具欄中展示了當前插件可以提供的大部分功能,方便我們在操作Document時快速選取使用。

開發工具欄主要使用NSStackView、NSButton、NSImage以及NSFont這幾個類,如果沒有開發過macOS應用的同學可能對這些類有些陌生,可以類比iOS開發中以UI作為前綴的控件類,NS前綴主要是AppKit以及Foundation的相關類,MS前綴則是Skecth的相關類,CA、CF前綴為核心動畫庫和核心基礎類。

下面的代碼記錄了創建工具欄的關鍵步驟,更為詳細的操作可以參考一些Github倉庫,比如sketch-plugin-boilerplate等。

const?contentView?=?context.document.documentWindow().contentView(); const?stageView?=?contentView.subviews().objectAtIndex(0);//1.創建toolbar const?toolbar?=?NSStackView.alloc().initWithFrame(NSMakeRect(0,?0,?27,?420)); toolbar.setBackgroundColor(NSColor.windowBackgroundColor()); toolbar.orientation?=?1;//2.創建Button const?button?=??NSButton.alloc().initWithFrame(rect) const?Image?=?NSImage.alloc().initWithContentsOfURL(imageURL) button.setImage(image) button.setTitle("數據填充") button.setFont(NSFont.fontWithName_size('Arial',11))//3.將Button加入toolbar toolbar.addView_inGravity(button,?gravityType);//4.將toolbar加入SketchWindow const?views?=?stageView.subviews() const?finalViews?=?[] for?(let?i?=?0;?i?<?views.count();?i++)?{finalViews.push(view)if(view[i].identifier()?===?'view_canvas'){finalViews.push(toolbar) }stageView.subviews?=?finalViewsstageView.adjustSubviews()

2. 創建WebView容器

除了通過CocoaScript創建原生NSPanel外,這里推薦使用官方的sketch-module-web-view快速創建WebView容器,它提供了豐富的API對窗口的展示樣式和行為進行定制,包括Frameless Window、Drag等,同時還封裝了WebView與插件層的通信的Bridge,使你可以輕松在"frontend" (the WebView)和"backend" (the plugin running in Sketch)之間發送消息。

//(1)方法一:原生方式加入webview const?panel?=?NSPanel.alloc().init(); panel.setFrame_display(NSMakeRect(0,?0,?panelWidth,?panelHeight),?true); const?wkwebviewConfig?=?WKWebViewConfiguration.alloc().init() const?webView?=?WKWebView.alloc().initWithFrame_configuration(CGRectMake(0,?0,?panelWidth,?panelWidth),wkwebviewConfig ) panel.contentView().addSubview(webView); webview.loadFileURL_allowingReadAccessToURL(NSURL.URLWithString(url),NSURL.URLWithString('file:///') ) //(2)方法二:使用官方的BrowserWindow import?BrowserWindow?from?"sketch-module-web-view"; const?browserWindow?=?new?BrowserWindow(options); const?webViewContents?=?browserWindow.webContents;webViewContents.executeJavaScript(`someGlobalFunctionDefinedInTheWebview(${JSON.stringify(someObject)})`).then(res?=>?{//?do?something?with?the?result})browserWindow.loadURL(require('./webview.html'))

3. 創建內容頁面

歷盡千辛萬苦,我們終于拿到了WebView,這下就可以發揮你“天馬行空”的想象力了。不管是React還是Vue,亦或只是一些簡單的靜態頁面對于你而言應該都不在話下。在完成界面開發后,只需通過Window向插件發送指令即可。下面的例子演示了積木插件的“數據填充”功能。

UI側

import?React?from?'react'; import?ReactDOM?from?'react-dom';//使用react搭建用戶頁面 ReactDOM.render(<Provider?store={store}><App?/></Provider>,?document.getElementById('root'));//傳遞用戶點擊填充類目給插件層,這里以填充文字為例 export?const?PostMessage?=?(name,?fillData)?=>?{try?{window.postMessage("fill-text-layer",?fillData);}?catch?(e)?{console.error(name,?"出現異常!!!"?+?fillData);} };?

插件側

??browserWindow.webContents.on('fill-text-layer',?function(s)?{//找到當前頁面documentconst?document?=?context.document;//獲取用戶選擇的layersconst?selection?=?Document.fromNative(document).selectedLayers;layers.forEach(item?=>?{//判斷layer類型是否為文字if?(item.type?===?'Text')?{//更新textlayeritem.text?=?value;}});? })

4. 還想加點出彩的功能

如果你還不滿足于此,說明你真的是個很愛學習,也很有潛力的開發同學。一個完善的插件需要包括交互層、API層、業務層、調試層以及發布層,每層各司其職,它們都在默默干好自己的工作。

前面的步驟,通過構件菜單欄、創建Webiew完成了交互層的開發;通過Webview的Bridge傳遞用戶操作到插件側代碼,之后調用Sketch API對圖層進行操作,這是API層的工作;而根據自身需求并依托交互層與API層的實現去編寫業務代碼,則是業務層的工作;至此,你應該就擁有了一個可運行的插件了。

但除此之外,在代碼編寫過程中還需要Lint組件輔助開發,發現問題需要使用各類Dev工具進行調試,通過QA驗證后,需要Cli工具打包并發布插件更新。這一小節,我們將簡單介紹一些基本的調試層和發布層知識。

積木Sketch Plugin結構

Webpack配置

Skpm默認采用Webpack作為打包工具。Webpack是一個現代JavaScript應用程序的靜態模塊打包器(Module Bundler)。當Webpack處理應用程序時,它會遞歸地構建一個依賴關系圖(Dependency Graph),其中包含應用程序需要的每個模塊,然后將所有這些模塊打包成一個或多個Bundle,需要在webpack.config.js進行配置,類似于Android中的Gradle,同樣支持各種插件。

Webpack處理流程示意

由于插件的開發者未必是前端同學,可能之前并沒有接觸過Webpack,因此我們在這里介紹它的一些常用配置,讓你有更多的時間關注業務代碼。第一次接觸Webpack是在去年一次公司內部的技術培訓上(美團技術學院提供了很多技術培訓課程,加入我們就可以盡情地在知識的海洋中遨游了),美團MRN項目的打包方案就是Webpack。

在前端圈有各種各樣的打包工具,比如Webpack、Rollup、Gulp、Grunt 等等。RN打包用的是Facebok實現的一套叫做Metro的工具,而美團MRN打包工具的選型是Webpack,因為Webpack具有強大的插件機制和豐富的社區生態,可以完成復雜的流水線打包工作,Webpack在Plugin開發中同樣發揮了非常重要的作用。Webpack有五個核心概念:

在插件開發中需要處理html、css、sass、jpg、style等各種文件,只有在Webpack中配置相應的Loader后,這些文件才能被處理。而且我們很可能遇到某些文件需要使用特定的插件,而其它文件又無需處理的情況。下面的示例中列舉了添加插件、對文件單獨處理以及參數配置這三個常用的基本操作。

module.exports?=?function?(config,?entry)?{?//常用功能1:增加插件config.module.rules.push({test:?/\.(svg)([\?]?.*)$/,use:?[{loader:?"file-loader",options:?{outputPath:?url?=>?path.join(WEBPACK_DIRECTORY,?url),publicPath:?url?=>?{return?url;}}}]});}//常用功能2:對文件單獨處理 if?(entry.script?===?"src/script.js")?{config.plugins.push(new?htmlWebpackPlugin({?})); }//常用功能3:定制js處理config.module.rules.push({test:?/\.jsx?$/,use:?[{?loader:?"babel-loader",options:?{presets:?["@babel/preset-react","@babel/preset-env"],plugins:?[//引入antd組件庫["import",{libraryName:?"antd",libraryDirectory:?"es",style:?"css"}]]}}]});

ESLint配置

JavaScript是一門非常靈活的語言,很多錯誤往往運行時才爆出,通過配置前端代碼檢查方案,在編寫代碼過程中可直接得到錯誤反饋,也可以進行代碼風格檢查,不僅提升了開發效率,同時對不良代碼編寫習慣也能起到糾正作用。在ESLint中需要配置基礎語法規則、React 規則、JSX規則等,由于Sketch插件的CocoaScript語法較為特殊,需要配置全局變量以此忽略AppKit中無法識別的類。

雖然,我們曾在部門組會中被多次“安利”ESLint的強大作用(這里給大家推薦一篇技術文章:ESLint 在中大型團隊的應用實踐),但如果不是做前端或者RN開發的同學,可能對于ESLint的復雜配置并不熟悉。可以直接使用Skpm提供的ESlint Config,里面配置了包含Sketch和macOS的頭文件的全局變量,而代碼格式化則推薦使用Prettier。

npm?install?--save-dev?eslint-config-sketch //或者直接使用帶prettier以eslint的skpm?template工程 $?skpm?create?my-plugin?--template=skpm/with-prettier

內容服務端化

Sketch推出的庫(Library)功能對于維護設計系統或風格指南,起到非常重要的作用,可以給團隊帶來高效工作體驗,甚至改變設計團隊工作方式和流程。我們通過組件庫可以在整個設計團隊中共享組件(Symbol),Library可以實現“一處更改,處處生效”,即使是關聯了遠程組件庫歷史的設計稿檢測到更新時,也會收到Sketch通知,確保工作中使用的是最新組件。

庫功能對美團外賣UI一致性起著至關重要的作用,這主要體現在兩方面:首先是實現設計風格沉淀,目前袋鼠UI已經形成了自己的獨特風格,外賣設計團隊根據設計規范,對符合UI一致性外賣業務場景的組件不斷進行抽象及建設,沉淀出越來越多的通用業務組件,這些組件需要及時擴充到Library中,供團隊成員使用;另外一個作用,則是保持團隊使用的均為最新組件,由于各種原因,組件的設計元素(色彩、字體、圓角等屬性)可能會發生變更,需要及時提醒團隊成員更新組件,保持所有頁面的一致性。

Sketch內置的iOS遠程組件庫

Library中的Symbol提示更新

庫組件自動更新,其實就是 “庫列表” - “庫 ID” - “外部組件原始 ID” 這三者的關聯。Sketch內部是靠UUID進行對象識別的,通過庫組件的庫ID,從庫面板的列表中,按照添加的時間從新到舊依次檢索所有未被禁用的、鏈接完好的庫,直到匹配到庫的ID ,然后查找該庫文件內是否有與庫組件SymbolID匹配的組件,如果包含且內容有差異就提醒更新,更新的過程實際上是內容替換。

我們通過以下步驟使用RSS技術共享Library供整個UI設計團隊使用:

  • 將Library Document 托管到公司內網服務器上。

  • 創建一個XML文件記錄版本信息和更新地址。

  • 最后使用Meyerweb URL編碼器之類的工具(或直接encodeURIComponent)對XML feed URL進行編碼并將其添加到以下內容:sketch://add-library?url=https://***.xml。

  • 將此URI在瀏覽器中打開即可。

<?xml?version="1.0"?encoding="UTF-8"?> <rss?version="2.0"?xmlns:atom="http://www.w3.org/2005/Atom"?xmlns:content="http://purl.org/rss/1.0/modules/content/"?xmlns:dc="http://purl.org/dc/elements/1.1/"?xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"><channel><title>My?Sketch?Library</title><description>My?Sketch?Library</description><image><url></url></image><item><title>My?Sketch?Library</title><pubDate>Wed,?23?Jun?2019?11:19:04?+0000</pubDate><enclosure?url="mysketchlibrary.sketch"?type="application/octet-stream"?sparkle:version="1"/></item></channel> </rss>

5. 開發流程小結

前面一口氣講述了很多內容,可能你一時無法消化。別急,慢慢來。我們這里對插件的開發流程作個簡要的總結:

  • 首先利用JavaScript 或CocoaScript開發操作面板。

  • 使用NPM安裝所需依賴。

  • 通過Bridge傳遞用戶操作到插件邏輯側,通過調用Skecth API對文檔進行處理。
    使用Webpack進行打包。

  • 通過測試后發布插件更新。

Sketch Plugin開發流程

別人可能沒告訴你的事兒

這部分主要記錄了積木Sketch Plugin開發過程中的踩坑經歷,但是這里,我們沒有貼大段的代碼,沒有直接告訴你答案,而是把分析問題的過程記錄下來。“授人以魚不如授人以漁”,相信只要你了解了這些分析技巧,即使之后遇到更多的問題,也可以輕(jia)松(ban)解決。

1. 與Xcode工程混合編譯

首先,我們要明確一個問題,為什么要使用XCode工程?

雖然官方提供了JS API并承諾持續維護,但這項工作一直處于Doing狀態,而且官方文檔更新緩慢,沒有明確的時間節點。因此,對于某些功能,比如我們想建一個具有Native Inspector Panel的插件,就不得不使用XCode進行開發。使用Xcode開發對于iOS開發者也更加友好,無需再學習前端界面開發知識。

這里推薦Invison的開發成員James Tang分享的博客文章《Sketch Plugin Xcode Template》,里面詳細描述了構建插件XCode工程的步驟,這也成為很多插件開發者遵循的范本。當然隨著Sketch的不斷升級,某些API已經不受支持,但作者講述的開發流程和思路依然沒有改變,具有很高的學習價值。

JavaScript //利用?Mocha加載framework var?mocha?=?Mocha.sharedRuntime(); [mocha?loadFrameworkWithName:frameworkName?inDirectory:pluginRootPath]

除此之外,Skpm中已經內置了@skpm/xcodeproj-loader,也可在JS中直接加載Framework。

JavaScript //加載framework const?framework?=?require('../xcode-project-name/project-name.xcodeproj/project.pbxproj'); const?nativeClass?=?framework.getClass('NativeClassName'); //獲取nib文件 const?ui?=?framework.getNib('NativeNibFile'); //也可以直接加載xib文件 const?NibUI?=?require('../xcode-project-name/view-name.xib') var?nib?=?NibUI() let?dialog?=?NSAlert.alloc().init() dialog.setAccessoryView(nib.getRoot()) dialog.runModal()

當然你也可以直接使用Github上一些知名的開源項目,有些會直接提供Framework供你使用,比如更改原生的toolbar:

2. 了解Electron

為什么在講述Sketch Plugin的時候,忽然會提到Electron?這里有一個小故事,某天上班打開大象(美團內部溝通軟件)。

MacOS版大象截圖

看到一條公眾號推送,是公司成立了Electron技術俱樂部(美團技術團隊內部自發成立了很多技術俱樂部),經過了解發現Electron基于Chromium和Node.js,可以使用HTML、CSS和JavaScript構建桌面應用程序,Electron負責其中比較復雜的部分,而開發者只需關心應用的核心需求即可。大象的Mac端就大量使用了Electron技術,用Web框架去開發桌面應用,可以直接復用Web現有的開發成果并獲得出色的運行效率。

我們就進行了簡單的學習,在之后的一段時間并沒有再去關注這項技術,直到某天在插件開發的過程中忽然遇到一個問題:在插件WebView顯示的情況下,在桌面空白處點擊使Sketch軟件失去焦點,整個App就會被隱藏。試了幾個流行的插件,發現大部分均有此問題,這給設計師的工作造成了諸多不便。試想,我只是去打開Finder找一個文件,你為什么要把我的軟件最小化?在Github上留言后,很快得到了項目開發者Mathieu Dutour的官方回復,原來只需要設置一個hidesOnDeactivate屬性即可。

等等!這不是Electron中的屬性么?仔細查看Readme才發現作者寫道“The API is mimicking the BrowserWindow API of Electron.”這下可方便多了!你想自定義窗口的表現,只需按照Electron的API設置即可,想想看其實Electron的工作方式是不是和Sketch Plugin如出一轍?

3. 更新原生屬性面板

為了更好地提升積木Sketch Plugin的使用體驗,UI同學通過建立公共Wiki記錄我們設計團隊在插件使用過程中的反饋建議,其中有一條很奇怪:“通過插件面板更新Layer屬性后,右側面板不刷新。”和上一個問題一樣,經測試其它插件大部分也有此問題,但是如何去更新右側屬性面板呢?翻閱了Sketch的API文檔還是“丈二和尚,摸不著頭腦”。這個時候想起了macOS開發的一個神器Interface Inspector,它可以在運行時分析正在運行的Mac應用程序的界面結構和屬性,非常強大。

開心的下載下來后,發現這個軟件上次的更新時間是6年前,忽然有了一種不祥的預感。果然Attach任何App時都會提示無法Attach,在macOS Catalina版本已經無法運行。可是這怎么能難倒“萬能”的程序員呢?我們查看系統報錯,發現是mach_inject_bundle_stub錯誤,查閱發現mach_inject_bundle_stub是Github上的一個開源庫,所以自己下載源碼重新編譯個Bundle包就可以了。

Attach成功后,就可以對Sketch的面板進行屬性分析了,是不是忽然感覺打開了新世界的大門?經過查閱發現右側面板在MSInspectorController中。如下圖所示:

Interface Inspector對Sketch進行運行時分析

下一步需要用Class-Dump工具來提取Sketch的頭文件,查看可以對inspector面板進行操作的所有方法:

通過class-dump得到的頭文件

不出所料,我們發現了reload(),猜測調用這個方法可以刷新面板,測試一下發現問題被修復了。如果你使用Sketch的JavaScript API的話,名稱不一定能完全對應,但是基本差不多,稍加分析也可以找到。這里只是教大家一個思路,這樣即使遇到其它問題,按照上面的步驟試試看,沒準就可以解決。

JavaScript //?reload?the?inspector?to?see?the?changes? var?sketch?=?require('sketch') var?document?=?sketch.getSelectedDocument() document.sketchObject.inspectorController().reload()

歡迎你的加入

如你所見,積木Sketch Plugin可以幫助設計團隊提升設計效率、沉淀設計語言以及減少走查負擔;讓RD同學面對新項目時,可以專注于業務需求而無需把時間耗費在組件的編寫上;減少QA工作量,保證控件質量無需頻繁回歸測試;幫助PM提高版本迭代效率及版本需求吞吐量,提供業務的快速拓展能力。

當然,我們除了希望制作一流的產品,也希望積木插件可以讓你在繁忙的工作中得以喘息。我們會繼續以設計語言為依托,以Skecth Plugin為抓手持續進行UI一致性建設,提高客戶端UI業務中臺能力。

可能對于一個前端工程師來說,對React、Webpack等配置可以信手拈來;對于一個iOS工程師來說,XCode調試、Objective-C語法是開發前的基礎;對于一個桌面工程師來說,對Electron、Hook分析已司空見慣。可Sketch Plugin開發就是這么有趣,雖然只是一個小小的插件,但它會讓你接觸各個端的技術,提升技術視野,但同樣會讓你在開發過程中遇到很多困難,曾經困擾了我好幾天的一個Webpack問題,部門同事幫我們聯系了一個開發經驗豐富的前端妹子去咨詢,對方一行代碼竟然就解決了。做你害怕做的事,然后你會發現,不過如此。

目前,積木插件開發還處于較為初級的階段,包括Mach(外賣自研動態化框架)實時預覽、模板代碼自動生成、自建插畫庫等功能已經在路上。除此之外,我們還規劃了很多激動人心的功能,需要制作更多精美的前端頁面,需要更完善的后臺管理。

這里加個廣告吧!不管你是FE、Android、iOS、后端,只要你對Bug毫不手軟,精益求精,都歡迎你加入我們外賣技術團隊,跟我們一起完善Sketch插件生態,讓積木插件可以為更多業務場景提供服務,為用戶提供卓越的體驗。讓我們一起用“積木”拼出萬千世界!

嗯,就先寫到這里吧!UI團隊同學說我們的實現和設計稿竟然差了一個像素,我們要回去改Bug了。

致謝

特別感謝優秀的設計師昱翰、沛東、淼林、雪美,他們在插件開發過程中給予的幫助。

特別感謝技術團隊的云鵬、曉飛在技術上給予的指導。

“前人栽樹,后人乘涼。”我們向優秀開源項目開發者致敬。

參考文獻

| Sketch Plugin開發官方文檔
| 深入理解Sketch庫
| 凹凸實驗室高大師Sketch插件開發實踐
| Sketch Plugin Xcode Template
| Beginning Sketch Plugins Development in Xcode
| 攜程機票Sketch插件開發實踐

----------? END? ----------

招聘信息

美團外賣長期招聘 Android、iOS、FE 高級/資深工程師和技術專家,歡迎加入外賣App大家庭。歡迎感興趣的同學發送簡歷至:tech@meituan.com(郵件標題注明:美團外賣技術團隊)

也許你還想看

|?微前端在美團外賣的實踐

|?美團外賣前端容器化演進實踐

|?Android視頻技術探索之旅:美團外賣商家端的實踐

總結

以上是生活随笔為你收集整理的积木Sketch Plugin:设计同学的贴心搭档的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲成人午夜av | 国产少妇在线观看 | 白丝av在线 | 欧美日韩中文在线观看 | 色婷婷视频 | 成人九九视频 | 免费av网址大全 | 91人人揉日日捏人人看 | 成人免费观看大片 | 久久在草 | 日韩中出在线 | 国产成人1区 | 久章草在线 | 超碰伊人网 | 在线中文字幕av观看 | 91超碰在线播放 | 国产成人久久精品 | 999久久精品 | 亚洲六月丁香色婷婷综合久久 | 手机看片国产日韩 | 成人免费在线观看电影 | 久久久久电影网站 | 特级大胆西西4444www | 国产成人av福利 | 精品国产一区二区三区在线 | 久久一及片| 国产福利免费在线观看 | 久久久久成人精品免费播放动漫 | 国产伦理精品一区二区 | 日日干美女| 亚洲成人av片在线观看 | 91日韩免费 | 亚洲天堂网在线视频 | 久久成人毛片 | 99久久日韩精品视频免费在线观看 | 日韩av片无码一区二区不卡电影 | 国产一区成人在线 | 日本三级不卡视频 | 激情五月婷婷综合 | 中文字幕日韩av | 国产精品久久精品 | 96香蕉视频 | 国产剧情在线一区 | 欧美亚洲专区 | 97天天干 | 国产在线精品一区二区三区 | a v在线观看 | 国产字幕在线播放 | 夜夜视频资源 | 免费视频91 | 九九精品久久 | 日韩网站在线观看 | 国产精品麻豆91 | 夜夜澡人模人人添人人看 | 天天色天天操综合网 | 国产一区视频在线观看免费 | 日韩高清免费电影 | 四虎免费av | 亚洲 欧美 精品 | 亚洲天天干 | 国产激情电影综合在线看 | 九九欧美视频 | 国产电影黄色av | 国产专区欧美专区 | 国产精品国产三级国产aⅴ无密码 | 欧美久久久久久久久久久久 | 中文字幕婷婷 | 国产麻豆视频网站 | 综合网在线视频 | 色99中文字幕 | 99久久99久国产黄毛片 | 91色视频| 国产盗摄精品一区二区 | 久久精品人人做人人综合老师 | 国产在线观看免费 | av中文字幕在线观看网站 | 国产91精品高清一区二区三区 | 午夜黄色影院 | 精品视频在线免费观看 | 欧美精品v国产精品v日韩精品 | 久久大片网站 | 欧美精品久久久久久久久久丰满 | 婷婷深爱网 | 国产精品久久精品国产 | 久久av网 | 精品高清美女精品国产区 | 超碰97国产在线 | 久久久精品免费观看 | 五月婷婷在线观看视频 | 欧美日韩成人 | 亚洲成人动漫在线观看 | a天堂在线看 | 欧美综合在线视频 | 色射色| 最近高清中文字幕在线国语5 | 成人免费在线视频观看 | 欧美色图亚洲图片 | 久久国产精品视频观看 | av免费成人| 99久久精品国产亚洲 | 成人国产精品久久久久久亚洲 | 激情五月五月婷婷 | 亚洲成人家庭影院 | 欧美极品一区二区三区 | 久操视频在线免费看 | 亚洲国产视频在线 | 中文字幕av免费观看 | 日韩一级理论片 | 欧美aⅴ在线观看 | 97超碰在 | 久久久久高清 | 色婷婷99 | 午夜视频在线观看网站 | 中文字幕在线看视频国产中文版 | 香蕉网在线播放 | 成年人在线观看 | 五月花激情| 伊人天堂久久 | 日本午夜在线观看 | www久久久 | 欧美日韩综合在线观看 | 久草久草在线观看 | 狠狠躁日日躁狂躁夜夜躁av | 午夜精品久久久久久久爽 | 97超视频在线观看 | 国产精品黄网站在线观看 | 中文字幕第一页在线vr | 男女精品久久 | 久久99免费视频 | 久久国产欧美日韩 | 人人爽人人爽人人爽学生一级 | 久久精品视频免费观看 | 精品视频一区在线 | 国产在线p | 探花视频网站 | 国产破处精品 | 久久手机精品视频 | 欧美在线视频一区二区三区 | 男女免费视频观看 | 狠狠88综合久久久久综合网 | 欧美日韩中文字幕视频 | 国产高清一级 | 亚洲麻豆精品 | 91久久国产精品 | 在线免费观看黄色 | 日韩黄色一级电影 | 97国产大学生情侣白嫩酒店 | 在线免费黄色 | 国产成人99av超碰超爽 | 国产一区二区在线视频观看 | 亚洲成人免费 | 成人黄色大片在线观看 | 国产免费一区二区三区最新 | 成人在线播放网站 | 精品a视频| 不卡的av片 | 人成午夜视频 | 女人18精品一区二区三区 | 成人免费在线视频观看 | 五月婷激情 | 久久99精品久久久久蜜臀 | 日韩久久精品一区二区三区 | 国产成本人视频在线观看 | 成人免费精品 | 亚洲永久精品视频 | 精品国产99国产精品 | 午夜.dj高清免费观看视频 | 免费久久99精品国产婷婷六月 | 久草在线视频新 | 成人午夜精品 | 欧美性生活大片 | 大胆欧美gogo免费视频一二区 | 久久成人高清 | 免费日韩 精品中文字幕视频在线 | 成人理论电影 | 国产欧美三级 | 婷婷激情影院 | 九色视频网 | 六月色婷婷 | 日韩免费中文 | 在线视频专区 | 久久天堂网站 | 欧美精品九九99久久 | 天堂av网站| 免费亚洲片 | 在线免费观看涩涩 | 在线不卡a | 日日操日日插 | 500部大龄熟乱视频使用方法 | 黄色片免费在线 | 国产高清视频免费在线观看 | 久久在线播放 | 日韩欧美亚洲 | 碰超在线97人人 | 91资源在线播放 | 在线看片一区 | 91久久久久久国产精品 | 欧美午夜视频在线 | 国产原创av在线 | 天天干天天干天天色 | 免费看成人片 | 成人午夜影院 | 黄色网址在线播放 | 午夜av在线电影 | 波多野结衣视频一区 | 国产麻豆精品一区 | 狠狠网| 又色又爽又激情的59视频 | 亚洲最新精品 | 97精品国产97久久久久久春色 | 欧美色图狠狠干 | 免费视频久久 | 日韩精品一卡 | 久久国内视频 | 五月天久久综合 | 国产成人三级在线观看 | 日韩中文字幕免费看 | 日韩手机在线观看 | 天天操天天舔天天爽 | 免费看黄色大全 | 97视频久久久 | www天天干 | 91自拍视频在线观看 | 97精品国产97久久久久久春色 | 激情在线网站 | 日韩a欧美 | 久久一区二区三区国产精品 | 国产资源精品在线观看 | 国产99区| 久久久久女教师免费一区 | 国产在线永久 | 久久久www成人免费精品张筱雨 | 久久国产精品99国产精 | 国产在线探花 | 中文字幕免费看 | 91麻豆文化传媒在线观看 | 伊人永久在线 | 视频一区在线播放 | 国产精品久久久免费看 | 黄色官网在线观看 | 一区二区三区电影 | 黄色在线观看网站 | 人人爽人人爽人人爽人人爽 | 99在线热播精品免费 | 国产精品日韩久久久久 | 国产精品久久久久久久久毛片 | 欧美日韩一区二区三区在线免费观看 | 欧美成人播放 | 在线观看国产www | 亚洲精品高清一区二区三区四区 | 欧美a视频在线观看 | 亚洲激情国产精品 | 349k.cc看片app | 天天射天天舔天天干 | 菠萝菠萝蜜在线播放 | 婷婷久月| 亚洲一级片在线观看 | 在线观看亚洲电影 | 深爱激情开心 | 草久中文字幕 | av中文字幕第一页 | 玖草在线观看 | 国产在线视频导航 | 国产高清不卡av | 亚洲三级黄色 | 国产精品a久久久久 | 成人91在线观看 | 免费看污片 | 亚洲国产精品500在线观看 | 国产精品久久久久久久久久久久 | 国产精品成人一区二区 | 精品一区二区在线看 | 国产一二区在线观看 | 亚洲无在线 | 国产网红在线观看 | 在线观看中文字幕第一页 | 中文字幕成人一区 | 在线观看亚洲精品 | 免费成人av | 综合久色 | 婷婷色综合网 | 欧美午夜理伦三级在线观看 | 美女黄频视频大全 | 黄色毛片在线观看 | 在线视频专区 | 日韩av一区二区三区在线观看 | 在线看中文字幕 | 97精品国产97久久久久久春色 | 久久久999精品视频 国产美女免费观看 | 天天综合人人 | 国产精品热视频 | 91超碰免费在线 | 国内精品中文字幕 | 国产视频资源在线观看 | 麻豆视频免费看 | 国产精品自拍在线 | 免费国产黄线在线观看视频 | 久久精品一二三 | 久久综合久久综合这里只有精品 | 中文字幕在线免费 | 久久综合操 | 久久伊人精品一区二区三区 | 69亚洲乱 | 免费av在线网站 | 亚洲一区 av | 日韩欧美xxx | 日日夜夜噜 | 欧美精品国产综合久久 | 国产中文字幕久久 | 97超碰国产精品女人人人爽 | 久久99久久久久久 | 色综合天天 | 亚洲毛片久久 | 奇米影视999 | 欧美疯狂性受xxxxx另类 | 九九热在线视频免费观看 | 日韩高清毛片 | 在线亚洲成人 | 久久精品视频在线免费观看 | 黄色国产精品 | 国产小视频在线免费观看 | 特级黄色片免费看 | 97超级碰碰碰视频在线观看 | 国产精品久久久毛片 | 久久久精品国产一区二区三区 | 天天艹天天爽 | 在线看黄色的网站 | 国产老妇av | 天天色天天射天天综合网 | 中文字幕在线视频一区二区三区 | 成人av一区二区兰花在线播放 | 人人爽人人av | 日本一区二区高清不卡 | 国产日韩欧美在线免费观看 | 在线观看一 | 国产成人精品一区二区在线观看 | 欧美日韩在线视频免费 | 五月天激情综合 | 国产在线播放不卡 | 91视频国产高清 | 激情网五月婷婷 | 亚洲国产美女久久久久 | 亚洲最新av网址 | 亚洲电影久久 | 国产成人精品亚洲日本在线观看 | 中文字幕精品一区二区三区电影 | 激情久久久 | 欧美激情综合五月色丁香小说 | 91精品视频播放 | 人人爽人人插 | 日本成址在线观看 | www.av中文字幕.com | 欧美污污网站 | 人人舔人人射 | 在线观看免费成人av | 激情综合网在线观看 | 美女视频黄是免费的 | 激情网色 | 在线成人观看 | 久久久精品久久日韩一区综合 | 久久久视频在线 | 免费又黄又爽 | 亚洲h在线播放在线观看h | 久久久性 | 亚洲欧洲日韩在线观看 | av片子在线观看 | 午夜精品福利一区二区三区蜜桃 | 黄色片免费看 | 久久夜视频 | 精品久久国产精品 | 日韩欧美有码在线 | 亚洲国产高清视频 | av在线网站免费观看 | 国产在线观看免 | 四虎永久免费网站 | 日韩欧美在线一区 | 亚洲aⅴ乱码精品成人区 | 九色视频网| 97国产在线视频 | 三级黄色在线观看 | 亚洲资源片| 国产精品成久久久久三级 | 国产精品岛国久久久久久久久红粉 | 狠狠操操网 | 中文字幕在线网址 | 欧美日韩网址 | 久久久久一区二区三区四区 | 国产免费久久av | 久久嗨 | 欧美日产一区 | 日韩电影在线一区二区 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 国产一区视频在线播放 | 日韩在线大片 | 中文在线字幕免 | 精品久久美女 | 精品久久久久久久久久久久久久久久 | www.天天射 | 成年人天堂com | 97免费视频在线播放 | 欧美在线观看禁18 | a在线播放 | 97超视频免费观看 | 国产成在线观看免费视频 | 午夜黄色 | 精品在线99 | 91资源在线观看 | 亚洲高清91 | 国产黄在线看 | av中文字幕在线免费观看 | 久久成人亚洲欧美电影 | av再线观看 | 久产久精国产品 | 亚洲欧洲av在线 | 麻豆视频在线播放 | 最近中文字幕免费大全 | 婷婷丁香狠狠爱 | 成人免费在线视频 | 久久久久久久久久久免费 | 久久人人爽人人片av | 亚州av网站| 99精品视频免费在线观看 | 黄色小说免费观看 | 国产福利91精品一区二区三区 | 人人精品| 视频在线一区二区三区 | 国产 一区二区三区 在线 | 日韩动漫免费观看高清完整版在线观看 | 叶爱av在线 | 久久久久久久久久久久久久电影 | 日韩在线观看中文字幕 | 丝袜制服综合网 | 在线观看国产v片 | 免费av福利| 欧美激情精品久久 | 日韩色中色 | 日韩av电影免费在线观看 | 国产性天天综合网 | 国产91电影在线观看 | 一区二区亚洲精品 | 1区2区3区在线观看 三级动图 | 99re中文字幕 | 黄网站大全 | 欧美激情精品久久久久久免费 | www.婷婷色| 天天综合天天做天天综合 | www激情com | 国产精品精品国产色婷婷 | 国产偷在线| 亚洲人久久久 | www久久精品 | 亚洲视频精品在线 | 国产又粗又猛又爽又黄的视频先 | 91亚色在线观看 | 国产精品免费视频观看 | 极品美女被弄高潮视频网站 | www蜜桃视频 | 天天操天天射天天爱 | 午夜影视一区 | 久久99国产精品久久99 | 久久激五月天综合精品 | 中文字幕免费高清av | 久久久久久久久久久高潮一区二区 | 久久综合久久伊人 | 亚洲国产精品一区二区久久hs | 久久久www成人免费精品 | 亚洲aⅴ乱码精品成人区 | 在线欧美小视频 | 欧美一区二区三区激情视频 | 国产精品毛片一区二区在线看 | 黄色毛片在线 | 麻豆观看| 亚洲一级片免费观看 | 国产剧情一区二区在线观看 | 亚洲经典视频在线观看 | 碰超在线| 丁香午夜 | 天天干天天草天天爽 | 亚洲精品日韩在线观看 | 久久免费观看视频 | 欧美日韩国内在线 | 美女很黄免费网站 | 狠狠狠色丁香综合久久天下网 | 国产精品一区二区在线播放 | 狠狠干夜夜 | 99免费在线观看 | 91久久国产综合精品女同国语 | 国产精品视频久久 | 黄色成人在线 | 中文字幕国产一区 | 男女全黄一级一级高潮免费看 | 在线视频免费观看 | 亚洲视频 在线观看 | 2020天天干夜夜爽 | 手机在线视频福利 | 免费视频久久久 | 久久久久免费精品 | 91精品视频在线免费观看 | 蜜臀久久99精品久久久无需会员 | 久久在线免费观看视频 | 色综合天天天天做夜夜夜夜做 | av高清一区二区三区 | 欧美 日韩 视频 | 中文字幕色综合网 | 西西444www| 综合色中文 | 亚洲一区久久久 | 亚洲国产视频在线 | 国产区精品 | 91亚洲精品国产 | 欧美视频99| 99久热在线精品视频成人一区 | 激情婷婷久久 | 美女视频a美女大全免费下载蜜臀 | 在线a视频免费观看 | 99九九热只有国产精品 | 国产精品美女久久久久久久久久久 | 999成人免费视频 | 天天操综| 综合久久精品 | 欧美精品久久久久a | 日批视频在线观看免费 | 欧美一级片免费观看 | 午夜少妇一区二区三区 | 亚洲永久精品在线观看 | 日韩精品免费一区二区三区 | 97超碰人人 | www国产亚洲精品久久麻豆 | 伊人久久在线观看 | 久久久性| 亚洲免费成人av电影 | 黄色的片子| 免费观看的黄色 | 国产成人一区二 | 亚洲久久视频 | 99热这里精品 | 国产一级黄色免费看 | 国产亚洲资源 | aaa毛片视频 | av不卡在线看| 99久久婷婷国产 | 人人澡人人爱 | 在线视频 区 | 日本黄色大片免费看 | 探花国产在线 | 久99久中文字幕在线 | 开心综合网 | 一本一本久久a久久精品综合 | 国产一区观看 | 国产第一页福利影院 | 色在线免费观看 | 中文av在线免费观看 | 欧美精品久| 午夜国产一区二区三区四区 | 欧美视频在线二区 | 五月天综合激情网 | 亚洲精品欧美精品 | 国产人成精品一区二区三 | 国产 日韩 在线 亚洲 字幕 中文 | 成年人网站免费在线观看 | 在线视频手机国产 | 天天操天天干天天综合网 | 91最新国产 | 成人av网站在线观看 | 国产亚洲精品久 | 国产欧美高清 | 久99久中文字幕在线 | 国产欧美日韩精品一区二区免费 | bbbbb女女女女女bbbbb国产 | 天天草天天 | 国产小视频在线看 | 黄色亚洲片 | 欧美成人精品欧美一级乱 | 91av在线视频免费观看 | 久久精品最新 | 丁香花五月 | 日韩av不卡在线播放 | 欧美一级黄色视屏 | 91久久久久久久一区二区 | 91精品啪在线观看国产81旧版 | 久久久精品电影 | 久久综合射| 久久福利在线 | 国产一区在线免费观看视频 | 91精品综合在线观看 | 麻豆影视在线观看 | 国产精品一区久久久久 | 91精品视频在线观看免费 | 免费观看性生交大片3 | 久久久久国 | 中文字幕一区二区三区乱码在线 | 欧美色黄 | 欧美一二三四在线 | 久久久久久久久久久黄色 | 久操视频在线观看 | 精品国产一区二区在线 | 看黄色91 | 视频国产一区二区三区 | 在线观看日韩国产 | 激情五月婷婷激情 | 国产一性一爱一乱一交 | 久久免费视频1 | 亚洲日本在线一区 | 中文字幕成人一区 | 黄色精品网站 | 97视频播放| 中文视频在线看 | 久久成人高清 | 久久xxxx| 在线精品视频在线观看高清 | 中文字幕免费观看视频 | 99久久久久国产精品免费 | www日韩视频 | www.狠狠插.com | 欧美精品一区二区三区一线天视频 | 亚洲国产精品999 | 91麻豆免费视频 | 人人干网站 | 热久久影视 | 天天艹天天干天天 | 国产精品美女久久久免费 | 成人在线观看免费视频 | 久久久麻豆精品一区二区 | 日韩精品免费在线播放 | 国模吧一区 | 日韩精品无码一区二区三区 | 国产精品久久人 | 国产高清精品在线 | 天天看天天操 | 福利视频第一页 | 国产福利91精品张津瑜 | 9999亚洲 | 成人福利在线播放 | 中文字幕国产亚洲 | 久久综合久久伊人 | 全黄色一级片 | 日韩av在线小说 | 在线观看中文字幕第一页 | 久久久久久久久久亚洲精品 | 天天爽人人爽夜夜爽 | 激情 婷婷| 色偷偷网站视频 | 日本久久久精品视频 | 免费国产亚洲视频 | 国产欧美精品一区二区三区 | 嫩模bbw搡bbbb搡bbbb | 在线小视频你懂得 | 久久精品三级 | 久久1电影院 | 国产剧情一区二区 | 黄av免费在线观看 | 欧美一区二区免费在线观看 | 91探花在线视频 | 亚洲国产欧洲综合997久久, | 欧美日韩啪啪 | 美女视频一区 | 久久久精品电影 | 欧洲黄色片 | 成人精品999 | 中文字幕乱视频 | 久久久91精品国产 | 成人免费视频播放 | 四虎永久精品在线 | 免费在线激情电影 | 色播激情五月 | 91视频免费看网站 | 日韩中文字幕免费视频 | 麻豆影视网站 | 五月婷婷视频在线观看 | 中文字幕免费在线看 | 亚洲涩涩网站 | 午夜影院先 | 日韩午夜电影 | 色多视频在线观看 | 91精品麻豆 | 久久96国产精品久久99漫画 | 国产一区自拍视频 | 在线视频观看亚洲 | 精品亚洲在线 | 99视频在线精品国自产拍免费观看 | 亚洲精品自在在线观看 | 久久免费看a级毛毛片 | 久久不射电影院 | www.香蕉| 国产精品第一页在线观看 | 99产精品成人啪免费网站 | 国产99久久久国产精品免费看 | 婷婷国产一区二区三区 | 国产福利91精品 | www.久草.com| 99精品在线免费 | 国产青青青 | www.色婷婷.com| 久久国产精品一区二区三区四区 | 99久久99久久精品免费 | 麻豆免费精品视频 | 久久国产精品系列 | 亚洲婷婷综合色高清在线 | 国产精品理论片 | 伊人伊成久久人综合网小说 | 精品中文字幕视频 | 中文字幕观看av | av电影免费在线看 | 亚洲伊人网在线观看 | 一区二区视频电影在线观看 | 国产亚洲婷婷免费 | 国产一二三四在线观看视频 | 日韩精品一区二区三区高清免费 | 精品国产伦一区二区三区观看说明 | 婷婷在线视频观看 | 日韩在线观看一区二区 | 国产高清无线码2021 | 亚洲伊人婷婷 | 蜜桃av久久久亚洲精品 | 日韩字幕在线观看 | 91亚州| 天天色图 | 国产一级久久久 | 97电影网手机版 | 国产成人精品一区二区三区在线 | 99精品免费| 国际精品网 | 日韩高清av在线 | 久久爱综合 | 午夜精品麻豆 | 免费在线播放 | 97网在线观看| 最新免费av在线 | 成人免费观看大片 | 精品国产观看 | 久久免费视频网站 | 狠狠色丁香婷婷综合基地 | 国产黄色精品在线观看 | 992tv在线成人免费观看 | 久久久国产精品亚洲一区 | 美女免费视频一区二区 | 国内精品久久久久久久久 | 国产精品一区二区av日韩在线 | 色天天中文 | 国产精品 日韩 | 久久国内精品视频 | 欧美一区二区三区在线观看 | 国产欧美综合在线观看 | 中文字幕日韩一区二区三区不卡 | 黄色一级动作片 | 国产一区二区三区在线 | 久久综合色天天久久综合图片 | 99精品免费久久久久久日本 | 91九色视频网站 | 亚洲特级毛片 | 99精品热视频只有精品10 | 久久久久免费精品国产小说色大师 | 一二区电影 | 免费观看久久 | 国产高清在线一区 | 丁香六月中文字幕 | 不卡中文字幕在线 | 精品一区 在线 | 在线观看av网站 | 91最新在线 | 日韩免费不卡视频 | 国产涩涩网站 | 婷婷爱五月天 | 六月丁香激情综合色啪小说 | 久久免费99 | 操操操夜夜操 | 亚洲天堂免费视频 | 久草精品视频 | 免费欧美 | 欧美日韩性生活 | 黄色大全视频 | 日韩在线观看视频一区二区三区 | 国产精品毛片一区 | 在线播放av网址 | 97在线视频免费观看 | 日韩小视频| 99久久综合国产精品二区 | 国产精品日韩久久久久 | 欧洲精品亚洲精品 | 九九免费视频 | 国产精品男女视频 | 99色资源 | 精品一区二区综合 | 91中文字幕视频 | 久久久人人爽 | 日韩精选在线观看 | 久久夜色网 | 精品视频久久久 | 日韩精品一区二区三区第95 | 欧洲精品视频一区二区 | 成人久久久电影 | 日韩视频a | 国产精品美女久久久久久2018 | 久久久久高清毛片一级 | 亚州精品视频 | 久久激情视频 久久 | 日韩字幕 | 日韩中文字幕在线不卡 | 99综合影院在线 | 免费黄色在线网站 | 五月天国产 | 天天要夜夜操 | 久久久国产精品网站 | 日韩天堂网 | 日韩欧美视频一区二区三区 | 99精品在线观看 | 黄a网| 午夜久久福利 | 日本一区二区三区免费观看 | 婷婷激情欧美 | 国产精品成久久久久三级 | 国产一区视频在线观看免费 | 正在播放国产91 | 欧美少妇xxx| 成人免费在线观看电影 | 欧美激情在线看 | 久久激情片 | 热久久99这里有精品 | 欧美精品色 | 成人av高清在线 | 久久久久久久久久久影院 | 久色 网 | 91成人欧美| 涩五月婷婷 | 国产精品一区二区三区免费看 | 2023av在线 | 欧美日韩在线观看不卡 | 一区二区三区在线影院 | 999成人 | 成 人 黄 色 视频 免费观看 | 中文字幕在线观看你懂的 | 久久精品欧美视频 | 亚洲国产精品影院 | 日韩欧美精品在线视频 | 精品国产一区二区三区免费 | 欧美资源在线观看 | 国产精品99蜜臀久久不卡二区 | 国产精品黑丝在线观看 | 国产五月婷婷 | 国产视频99 | www.久久久精品 | 午夜视频播放 | 精品久久久久一区二区国产 | 日韩在线一区二区免费 | 国产精品手机播放 | 1024手机基地在线观看 | 99久高清在线观看视频99精品热在线观看视频 | 亚洲午夜精品久久久 | 久久国产精品久久精品 | 亚洲成人av电影 | 国产在线视频在线观看 | 视频一区二区视频 | 亚洲婷婷综合色高清在线 | 国产精品欧美久久久久久 | 在线免费观看欧美日韩 | 日日夜夜精品 | 亚洲最大av | 天天鲁一鲁摸一摸爽一爽 | avove黑丝 | 国产精品久久精品 | av网站在线观看播放 | 亚洲无吗天堂 | 不卡视频在线 | 狠狠色狠狠色 | 丝袜网站在线观看 | 成人毛片100免费观看 | 99久久精品国产系列 | 天天草视频 | 狠狠色丁香久久婷婷综合五月 | 麻豆一区二区 | 99亚洲精品视频 | 亚洲高清资源 | 欧美孕交vivoestv另类 | 国产成人av福利 | 亚洲成人av免费 | 66av99精品福利视频在线 | 国产一区二区三区免费在线观看 | 国产黄色资源 | 97**国产露脸精品国产 | 成人av在线影视 | www91在线| 最新av在线免费观看 | 在线电影 你懂得 | 97电影院网| 在线观看av不卡 | 欧美日韩在线电影 | www在线免费观看 | 亚洲精品中文字幕在线 | 成人久久18免费网站图片 | 99在线热播精品免费 | 8x成人免费视频 | 五月天婷亚洲天综合网鲁鲁鲁 | 婷婷久久综合九色综合 | 国产精品黄色 | 国产精品久久一 | av在线一级 | 欧美精品小视频 | 久久人人97超碰精品888 | 亚洲精品www久久久久久 | 亚洲精品三级 | 亚洲欧美综合精品久久成人 | 国产最新福利 | 国产精品久久久久毛片大屁完整版 | 久久伊人精品一区二区三区 | 日本电影黄色 | 99久久精品国产毛片 | 免费 在线 中文 日本 | 亚洲精品中文字幕视频 | 92精品国产成人观看免费 | 亚洲综合网站在线观看 | 丁香久久综合 | 97精品久久人人爽人人爽 | 日韩,中文字幕 | 久久精品在线视频 | 一本一本久久a久久精品牛牛影视 | 不卡av在线 | av黄色免费看 | 日韩,中文字幕 | 一区二区在线不卡 | 国产91粉嫩白浆在线观看 | 日韩免费视频网站 | 久久久久久久久久久黄色 | 国产一区视频在线 | 精品欧美一区二区在线观看 | 综合色天天| 久久久蜜桃 | 成人影音在线 | 91成人精品一区在线播放69 | 综合久久网站 | 欧美动漫一区二区三区 | 亚洲精品一区二区三区高潮 | 免费在线观看日韩欧美 | 在线观看国产区 | 四虎影视成人永久免费观看亚洲欧美 | 日韩欧美在线综合网 | 欧美日韩国产精品一区二区 | 日韩艹| 精品一二 | 黄色国产精品 | 久久这里只有精品久久 | 夜添久久精品亚洲国产精品 | 日本三级吹潮在线 | 在线91视频 | 在线看一区 | 欧美日韩一级视频 | 四虎在线免费视频 | 久久伦理电影网 | 精品日韩在线一区 | 91精品毛片 | 狠狠色丁香九九婷婷综合五月 | 久操97| 亚洲一区二区高潮无套美女 | 国产 av 日韩 | 狠狠黄 | 日韩美在线观看 | 久久久久国产精品免费 | 五月导航 | 亚洲观看黄色网 | 国产精品大全 | 国产亚洲精品日韩在线tv黄 | 久久久精华网 | 国产精品麻豆视频 | 精品欧美日韩 | 国产色秀视频 | 国产小视频国产精品 | 国产精品日韩久久久久 | 涩五月婷婷 | 国产精品久久99综合免费观看尤物 | 国产 一区二区三区 在线 | 激情五月婷婷综合网 | 免费看久久久 | 91热这里只有精品 | 在线观看91av | 国产精国产精品 | 欧美男同视频网站 | 色欧美成人精品a∨在线观看 | 亚洲激情影院 | 在线视频a| 久久久污| 中文亚洲欧美日韩 | 久久成人亚洲欧美电影 | 久草剧场| 日韩久久久久久久久 | a级国产乱理伦片在线观看 亚洲3级 | 夜夜操网站 | 亚洲一区欧美激情 | 日韩在线视| 久久精品国产免费 | 国产亚洲精品v | 91一区二区三区久久久久国产乱 | 国产精品久久电影观看 | 天天操操操操操 | 99国产视频在线 | 激情亚洲综合在线 | 欧美日韩国产在线精品 | 香蕉91视频 | 久久久久久久久影院 | 亚洲精品国产精品国自 |