Web端最快且最具內(nèi)存靈活性的全文搜索庫,零依賴性。
Github地址:https://github.com/nextapps-de/flexsearch
github截圖
在原始搜索速度方面,F(xiàn)lexSearch優(yōu)于每一個搜索庫,并提供靈活的搜索功能,如多字段搜索,語音轉(zhuǎn)換或部分匹配。 根據(jù)使用的選項(xiàng),它還提供最高內(nèi)存效率的索引。 FlexSearch引入了一種新的評分算法,稱為“上下文索引”,基于預(yù)先評分的詞典字典體系結(jié)構(gòu),與其他庫相比,實(shí)際執(zhí)行的查詢速度提高了1,000,000倍。 FlexSearch還為您提供非阻塞異步處理模型以及Web工作者,以通過專用平衡線程并行地對索引執(zhí)行任何更新或查詢。
可以到官網(wǎng)下載經(jīng)過壓縮的js文件或者使用cdn,也可以使用npm安裝
//使用最新版: <script src="https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@master/dist/flexsearch.min.js"></script> //或者特定版 <script src="https://cdn.jsdelivr.net/gh/nextapps-de/flexsearch@0.3.51/dist/flexsearch.min.js"></script>
npm install flexsearch
var index=new FlexSearch(); //或者 var index=FlexSearch.create(); //或者給定一個默認(rèn)值 var index=new FlexSearch("speed"); //自定義配置 var index=new FlexSearch({ // default values: encode: "balance", tokenize: "forward", threshold: 0, async: false, worker: false, cache: false }); //在或者 var index=new FlexSearch("memory", { encode: "balance", tokenize: "forward", threshold: 0 });
Index.add(id, string)
index.add(10025, "John Doe");
Index.search(string | options, <limit>, <callback>)
index.search("John");
index.search("John", 10);
//基于回調(diào)函數(shù) index.search("John", function(result){ // array of results }); //基于Promise index.search("John").then(function(result){ // array of results }); //es6寫法 async function search(query){ const result=await index.search(query); // ... }
index.search({ query: "John", limit: 1000, threshold: 5, // >=threshold depth: 3, // <=depth callback: function(results){ // ... } }); //或者 index.search("John", { limit: 1000, threshold: 5, depth: 3 }, function(results){ // .... });
var response=index.search("John Doe", { limit: 5, page: true }); index.search("John Doe", { limit: 10, page: response.next });//下一頁
獲取查詢建議
index.search({ query: "John Doe", suggest: true });
啟用建議后,將填寫所有結(jié)果(直到限制,默認(rèn)為1000),并按相關(guān)性排序相似的匹配。
Index.update(id, string)
index.update(10025, "Road Runner");
Index.remove(id)
index.remove(10025);
index.clear();
index.destroy();
Index.init(<options>)
//使用相同配置重新初始化 index.init(); //使用新的配置重新初始化 index.init({ /* options */ }); //重新初始化會銷毀舊的索引
var length=index.length;
var index=index.index;
寄存器的格式為“@”+ id
請不要手動修改寄存器,用作只讀即可
FlexSearch.registerMatcher({REGEX: REPLACE})
FlexSearch.registerMatcher({ '?': 'a', // replaces all '?' to 'a' 'ó': 'o', '[?úù]': 'u' // replaces multiple });
index.addMatcher({ '?': 'a', // replaces all '?' to 'a' 'ó': 'o', '[?úù]': 'u' // replaces multiple });
通過在索引創(chuàng)建/初始化期間傳遞函數(shù)來分配自定義編碼
var index=new FlexSearch({ encode: function(str){ // do something with str ... return str; } });
編碼器函數(shù)獲取一個字符串作為參數(shù),返回修改后的字符串
直接調(diào)用自定義編碼器:
var encoded=index.encode("sample text");
FlexSearch.registerEncoder(name, encoder)
所有實(shí)例都可以共享/使用全局編碼
FlexSearch.registerEncoder("whitespace", function(str){ return str.replace(/\s/g, ""); });
初始化索引并分配全局編碼
var index=new FlexSearch({ encode: "whitespace" });
直接調(diào)用全局編碼
var encoded=FlexSearch.encode("whitespace", "sample text");
FlexSearch.registerEncoder('mixed', function(str){ str=this.encode("icase", str); // built-in str=this.encode("whitespace", str); // custom // do something additional with str ... return str; });
在創(chuàng)建/初始化期間定義私有自定義標(biāo)記
var index=new FlexSearch({ tokenize: function(str){ return str.split(/\s-\//g); } });
Stemmer: several linguistic mutations of the same word (e.g. "run" and "running")
Filter: a blacklist of words to be filtered out from indexing at all (e.g. "and", "to" or "be")
在創(chuàng)建/初始化期間分配私有自定義詞干分析器或過濾器
var index=new FlexSearch({ stemmer: { // object {key: replacement} "ational": "ate", "tional": "tion", "enci": "ence", "ing": "" }, filter: [ // array blacklist "in", "into", "is", "isn't", "it", "it's" ] });
使用自定義詞干分析器
var index=new FlexSearch({ stemmer: function(value){ // apply some replacements // ... return value; } });
使用自定義過濾器
var index=new FlexSearch({ filter: function(value){ // just add values with length > 1 to the index return value.length > 1; } });
或者將詞干分析器/過濾器全局分配給一種語言
Stemmer作為對象(鍵值對)傳遞,過濾為數(shù)組
FlexSearch.registerLanguage("us", { stemmer: { /* ... */ }, filter: [ /* ... */ ] });
或者使用一些預(yù)定義的詞干分析器或首選語言的過濾器
<html> <head> <script src="js/flexsearch.min.js"></script> <script src="js/lang/en.min.js"></script> <script src="js/lang/de.min.js"></script> </head> ...
現(xiàn)在您可以在創(chuàng)建/初始化期間分配內(nèi)置詞干分析器
var index_en=new FlexSearch({ stemmer: "en", filter: "en" }); var index_de=new FlexSearch({ stemmer: "de", filter: [ /* custom */ ] });
在Node.js中,只需要語言包文件即可使用它們
require("flexsearch.js"); require("lang/en.js"); require("lang/de.js");
本文知識大致翻譯了部分使用方法,更加強(qiáng)大和完整的用法參考官方Github文檔,里面有更加詳細(xì)的用法!
好,本文屬于技術(shù)類文章,建議有本領(lǐng)域的技術(shù)基礎(chǔ)者閱讀,以便更好地理解。
這篇文章分兩個步驟講解,如下:
第一步:什么是 flex + div 呢?
flex 是CSS的一套布局方案,一個一維布局模型;是Flexible Box的縮寫,意思就算“彈性布局”,理解flex概念使用,記住下面兩點(diǎn)即可:
div 其就是一個普通HTML元素標(biāo)簽,大部分內(nèi)容都是可以基于這個元素標(biāo)簽封裝的,形成一個復(fù)用性大,共用性好的新元素標(biāo)簽。
第二步:如何使用 flex + div 來繪制作品,哪些場景的作品可以使用?
首先如何使用,下面我們直接看一個封裝好的例子元素標(biāo)簽,給拆解出來講解如何使用,其他舉一反三即可:
圖-1-1
這是一個普通貨品上架的卡片信息內(nèi)容,它就是一個flex+div結(jié)構(gòu)繪制,被紅線圈出來,都是一個個的flex+div內(nèi)容布局,外層定義flex容器,內(nèi)部就是該flex容器子元素內(nèi)容,這些內(nèi)容子元素,都flex布局排列x-y軸方向的信息,簡單吧!所以幾乎大部分的頁面內(nèi)容都可以使用這flex+div方式可以封裝你的業(yè)務(wù)標(biāo)簽組件,以便復(fù)用,flex布局元素排列好,設(shè)置每個元素的內(nèi)外邊距、樣式、字體、顏色這些標(biāo)簽屬性,就看到這樣一個通用的普通組件標(biāo)簽場景了。
簡單吧!這就是一個flex+div繪制互聯(lián)網(wǎng)作品,商品上架的貨品卡片,多個就復(fù)用該標(biāo)簽組件形成一個列表展示了。
如下代碼標(biāo)簽,就是這個貨品使用flex + div方式繪制的,只有你確定了頁面內(nèi)容flex結(jié)構(gòu)層級,即可快速繪制出來:
圖-1-2
哪些場景會用到了,網(wǎng)站、小程序、管理系統(tǒng)等這些互聯(lián)網(wǎng)作品基本都會用它的,按業(yè)務(wù)需求場景去封裝你的作品輸出服務(wù)。
簡單吧!學(xué)會flex + div,在你的互聯(lián)網(wǎng)產(chǎn)品繪制之路,快速便捷的實(shí)戰(zhàn),無論是自由原創(chuàng)、還是看圖仿制都是可以的,不限制你的想象空間,就像我們畫家一樣,可以自由創(chuàng)作作品,也可看圖,看景創(chuàng)景作品,實(shí)際工作是會溝通好場景需求,在去創(chuàng)作,才服務(wù)滿足顧客需求意向,以更好去交付獲得收益。
拜拜!下期再見!
要: 作者:閑魚技術(shù)-意境 Flutter作為一種全新的響應(yīng)式,跨平臺,高性能的移動開發(fā)框架。從開源以來,已經(jīng)得到越來越多開發(fā)者的喜愛。閑魚是最早一批與谷歌展開合作,并在重要的商品詳情頁中使用上線的公司。一路走來,積累了大量的開發(fā)經(jīng)驗(yàn)。
Flutter作為一種全新的響應(yīng)式,跨平臺,高性能的移動開發(fā)框架。從開源以來,已經(jīng)得到越來越多開發(fā)者的喜愛。閑魚是最早一批與谷歌展開合作,并在重要的商品詳情頁中使用上線的公司。一路走來,積累了大量的開發(fā)經(jīng)驗(yàn)。雖然越來越多的技術(shù)大牛在flutter世界中弄得風(fēng)聲水起,但是肯定有很多的flutter小白希望能快速上手,享受flutter編程的樂趣。本文就是面向剛剛踏上futter的同學(xué),從Flutter體系中最基本的一個概念widget入手學(xué)習(xí)Flutter。希望能助力每一位初學(xué)者。
可能大家要問的第一個問題是為什么從Widget開始?
從flutter的架構(gòu)圖中不難看出widget是整個視圖描述的基礎(chǔ)。Flutter 的核心設(shè)計(jì)思想便是
即一切即Widget。在flutter的世界里,包括views,view controllers,layouts等在內(nèi)的概念都建立在Widget之上。widget是flutter功能的抽象描述。所以掌握Flutter的基礎(chǔ)就是學(xué)會使用widget開始。
本文會從大家熟悉的UI繪制視角來介紹flutter組件和布局的基礎(chǔ)知識。首先羅列了UI開發(fā)中最為常用,最為基礎(chǔ)的組件。下面逐一進(jìn)行介紹。
Text幾乎是UI開發(fā)中最為重要的組件之一了,UI上面文字的展示基本上都要靠Text組件來完成。Flutter提供了原生的Text組件。Text的配置屬性是很豐富的,屬性主要分為兩個部分一個是對齊&顯示控制相關(guān)的在Text類的屬性中,另一類是樣式相關(guān)的屬性使用單獨(dú)的類TextStyle進(jìn)行控制。跟native控件相比(以android為例),Text的組件基本上提供了同等的能力,并且提供了更加豐富的樣式裝飾能力。詳細(xì)的屬性可以參考官方文檔flutter text.(https://docs.flutter.io/flutter/widgets/Text-class.html?spm=a2c4e.11153940.blogcont634392.6.14f56cd4VVp3Nm)
設(shè)置文字&文字大小&顏色&行數(shù)限制&文本對齊
效果如下:
圖片也是UI部分開發(fā)最為重要的組件之一。在能看圖隨看文字的年代,圖片是頁面展示的重中之重!Flutter同樣原生提供了Image組件。下面重點(diǎn)介紹一下幾個重點(diǎn):
怎樣設(shè)置圖片顯示的縮放方式呢?
Flutter中的圖片縮放是fit字段來控制的。這是對最終圖片展示效果影響很大的一個參數(shù),也是容易出錯的點(diǎn)。下面逐個分析一下flutter Image組件提供的縮放方式。
縮放屬性值在BoxFit枚舉中
下面列出的圖片是flutter官方對各種縮放做的圖片示例。基本上都表述很清楚了,就整理出來供大家查閱。
怎樣從各種來源加載圖片?
默認(rèn)的Image組件不能直接顯示圖片,他需要一個ImageProvider來提供具體的圖片資源的(即Image中的image字段需要賦值)。咋一看這確實(shí)非常麻煩,但是實(shí)際上ImageProvider并不需要完全重新自己實(shí)現(xiàn)。在Image類中目前提供了一下幾個實(shí)現(xiàn)好的ImageProvider,基本能滿足常見的需求。
Image同樣支持GIF圖片
網(wǎng)絡(luò)請求Image是大家最常見的操作。這里重點(diǎn)說明兩個點(diǎn):
ImageCache是ImageProvider默認(rèn)使用的圖片緩存。ImageCache使用的是LRU的算法。默認(rèn)可以存儲1000張圖片。如果覺得緩存太大,可以通過設(shè)置ImageCache的maximumSize屬性來控制緩存圖片的數(shù)量。也可以通過設(shè)置maximumSizeBytes來控制緩存的大小(默認(rèn)緩存大小10MB)。
如果想要使用cdn優(yōu)化,可以通過url增加后綴的方式實(shí)現(xiàn)。默認(rèn)實(shí)現(xiàn)中沒有這個點(diǎn),但是考慮到cdn優(yōu)化的可觀收益,建議大家利用好這個優(yōu)化。
在實(shí)際開發(fā)中,考慮到圖片加載速度可能不能達(dá)到預(yù)期。所以希望能增加漸入效果&增加placeHolder的功能。Flutter同樣提供的這樣的組件——FadeInImage。
FadeInImage也提供了從多種渠道加載圖片的能力。這塊跟上面所說差異不大。這里不再贅述。
Flutter的設(shè)計(jì)思想就是完全的widget化。這也就是說連最基本的padding,Center都是widget。設(shè)想一下如果每次寫view,連padding,Center都要自己包一個組件是一種怎樣的體驗(yàn)?作為一個工程師,別給只給我談思想,實(shí)際操作的操作效率也同樣非常重要。flutter 官方也意識到了這個問題,他們從實(shí)際編寫效率的角提供了一個友好高效的封裝,這就是Container!首先沒有任何疑問,Container 本身也是一個widget。但是他卻提供了對基礎(chǔ)widget的封裝,提高了UI基礎(chǔ)裝飾能力的表達(dá)效率。Container類似于android中的ViewGroup。
相信大部分的屬性大家都會感覺非常親切,結(jié)合代碼注釋都比較容易理解,這里就不再贅述。其中需要重點(diǎn)解釋一下的是:Decoration和BoxConstraints。
Decoration是對Container進(jìn)行裝飾的描述。其概念類似與android中的shape。一般實(shí)際場景中會使用他的子類BoxDecoration。BoxDecoration提供了對背景色,邊框,圓角,陰影和漸變等功能的定制能力。
需要注意幾個點(diǎn):
BoxConstraints其實(shí)是對Container組件大小的描述。BoxConstraints屬性比較簡單。如果不太清楚可以研究一下盒子模型。這里有個點(diǎn)需要重點(diǎn)說明一下:
手勢操作是最常見的UI交互操作。在Flutter中手勢識別也是一個widget!這點(diǎn)對新人來說又是一個新鮮的地方。通常來說可以通過GestureDetector類來完成點(diǎn)擊事件的處理。使用時只需要將GestureDetector包裹在目標(biāo)widget外面,再實(shí)現(xiàn)對應(yīng)事件的函數(shù)即可。從點(diǎn)擊到長按,從縮放到拖動,這個類基本上都有相應(yīng)的實(shí)現(xiàn)。具體可以參見組件文檔。
頁面布局應(yīng)該是UI編寫最為根本的知識,其主要的描述的是父子組件子子組件之間的位置關(guān)系。首先我們理解一下官方文檔的邏輯:
將布局分為單孩子和多孩子是Flutter布局的一大特色。這點(diǎn)對native研發(fā)同學(xué)來說會比較新鮮。單孩子組件主要繼承自SingleChildRenderObjectWidget。這些組件能提供豐富的裝飾能力(例如container),也能提供部分特定的布局能力(例如center)。多孩子組件繼承自MultiChildRenderObjectWidget,能提供更加豐富的布局能力(Flex,Stack,flow),但幾乎沒有裝飾的能力。下面介紹幾個重點(diǎn)布局:
Flutter在布局上也提供了完整的Flex布局能力。但是在Flutter官方文檔中Layout Widgets,是看不到任何Flex的影子的。映入眼簾的卻是Row,Column,這些是什么鬼?其實(shí)不難發(fā)現(xiàn)類似Row,Column 這樣的組件,他們的基類都是Flex。Row和Column差別是設(shè)置了不同的flex-direction。而之所這么設(shè)計(jì),是因?yàn)镕lutter的widget從開始設(shè)計(jì)之初就考慮到UI布局語義保持的重要性。這塊應(yīng)該部分借鑒了前端的經(jīng)驗(yàn),極力避免一個div搞定全部頁面的尷尬(當(dāng)然flutter也可以使用Flex來做同樣的事情,但是并不建議這么做)。
Flutter使用的Flex模型基本上跟傳統(tǒng)的Css類似。這塊前端同學(xué)可以快速上手。但是Flex對于客戶端同學(xué)來說是一種全新的布局方式。Flex的基礎(chǔ)知識可以參看flex布局基礎(chǔ)。由于篇幅有限這里不展開敘述。這里只重點(diǎn)強(qiáng)調(diào)一個點(diǎn):
如下圖flex布局概念如下:
flex通過direction設(shè)置了flex的主軸方向即main axis。和主軸垂直的方向叫做cross axis。flex布局中對子布局的控制是從main axis 和cross axis兩個方向上進(jìn)行的。例如居中有main axis居中和cross axis居中。兩者都居中才是容器的完全居中。這點(diǎn)是客戶端同學(xué)可能會容易弄混的地方。重點(diǎn)關(guān)注一下。
ok,看完這些知識,我們實(shí)際需求角度實(shí)際操作幾個case來熟悉一下Flex。
在實(shí)際開發(fā)中,還是需要在一些Widgets的上面再覆蓋上新的Widgets。這時候就需要層式布局了。這種布局在Native上,以android為例,類似于relativeLayout 或者FrameLayout。在Flutter中使用的是Stack。
實(shí)際使用中Stack中的子Widgets分為兩種:
對于non-positioned children, 我們通過控制Stack的alignment屬性來控制對齊方式。Positioned的布局方式類似于H5&weex中的position布局中的absolute布局方式。通過設(shè)置距離父組件上下左右的距離,Positioned對象能在Stack布局中更加靈活的控制view的展現(xiàn)方式。
當(dāng)你看完Flutter Widge文檔的時候,我們突然發(fā)現(xiàn)一個略顯尷尬的問題:組件是否顯示怎么控制?貌似所有的組件中都沒有這個屬性!這不坑了,咋辦?
目前看方法無非如下幾個:
核心將該真實(shí)widget或者widget樹從renderTree中移除。
具體到實(shí)踐級別主要分為兩個:
在父容器的children字段的list中,刪除掉對應(yīng)的cell。
Offstage 是一個widget。Offstage的offstage屬性設(shè)置為true,那么Offstage以及他的child都將不會被繪制到界面上。
sample code如下:
設(shè)置widget的透明度,使之不可見。但是這樣的方法是副作用的。因?yàn)檫@個對應(yīng)的widget樹是已經(jīng)經(jīng)過了完整的layout&paint過程,成本高。同時設(shè)置透明度本身也要耗費(fèi)一定的計(jì)算資源,造成了二次浪費(fèi)。需要注意的是即便變透明了,占據(jù)的位置還在。大家慎重選擇使用。
sample code如下:
visibility的控制還是比較麻煩的。這是Flutter設(shè)計(jì)上不符合正常習(xí)慣的一個點(diǎn),需要大家重點(diǎn)關(guān)注。
widget是immutable的,發(fā)生變化的時候需要重建,所以談不上狀態(tài)。StatefulWidget 中的狀態(tài)保持其實(shí)是通過State類來實(shí)現(xiàn)的。State擁有一套自己的生命周期,下面做一個簡單的介紹。
生命周期狀態(tài)圖如下:
幾個注意點(diǎn)
需要指出的是如果想要知道App的生命周期,那么需要通過WidgetsBindingObserver的didChangeAppLifecycleState 來獲取。通過該接口可以獲取是生命周期在AppLifecycleState類中。常用狀態(tài)包含如下幾個:
一個實(shí)際場景中的例子:
在不考慮suspending的情況下:從后臺切入前臺生命周期變化如下:
從前臺壓后臺生命周期變化如下:
Dart語言對大部分開發(fā)者而言是很陌生的一種語言。google為啥會選擇如此'冷門'的語言來開發(fā)flutter?主要原因如下:
個人認(rèn)為是兩個主要的點(diǎn):
可能剛開始接觸flutter的同學(xué)最疑惑的一個問題就是widget和view的關(guān)系了。那么簡單分析一下:
widget是對頁面UI的一種描述。他功能類有點(diǎn)似于android中的xml,或者web中的html。widget在渲染的時候會轉(zhuǎn)化成element。Element相比于widget增加了上下文的信息。element是對應(yīng)widget,在渲染樹的實(shí)例化節(jié)點(diǎn)。由于widget是immutable的,所以同一個widget可以同時描述多個渲染樹中的節(jié)點(diǎn)。但是Element是描述固定在渲染書中的某一個特定位置的點(diǎn)。簡單點(diǎn)說widget作為一種描述是可以復(fù)用的,但是element卻跟需要繪制的節(jié)點(diǎn)一一對應(yīng)。那element是最終渲染的view么?抱歉,還不是。element繪制時會轉(zhuǎn)化成rendObject。RendObject才是真正經(jīng)過layout和paint并繪制在屏幕上的對象。在flutter中有三套渲染相關(guān)的tree,分別是:widget tree, element tree & rendObject tree。三者的渲染流程如下:
那可能有人會問,為什么需要增增加中間這層的Element tree?
flutter是響應(yīng)式的框架。在某一時刻頁面的布局,可能受不同的輸入源的影響。Element這層實(shí)際上做了對某一時刻事件的匯總,在將真正需要修改的部分同步到真實(shí)的rendObject tree上。這么做有兩個好處:
StatelessWidget是狀態(tài)不可變的widget。初始狀態(tài)設(shè)置以后就不可再變化。如果需要變化需要重新創(chuàng)建。StatefulWidget可以保存自己的狀態(tài)。那問題是既然widget都是immutable的,怎么保存狀態(tài)?其實(shí)Flutter是通過引入了State來保存狀態(tài)。當(dāng)State的狀態(tài)改變時,能重新構(gòu)建本節(jié)點(diǎn)以及孩子的Widget樹來進(jìn)行UI變化。注意:如果需要主動改變State的狀態(tài),需要通過setState()方法進(jìn)行觸發(fā),單純改變數(shù)據(jù)是不會引發(fā)UI改變的。
更多資訊,盡在阿里云科技快訊~
來科技快訊看新聞鴨~
快點(diǎn)關(guān)注我認(rèn)識我愛上我啊~~~
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。