Day06 - Fetch、filter、正則表達式實現快速古詩匹配

Day06 - Fetch、filter、正則表達式實現快速古詩匹配

做者:©liyuechun
簡介:JavaScript30Wes Bos 推出的一個 30 天挑戰。項目免費提供了 30 個視頻教程、30 個挑戰的起始文檔和 30 個挑戰解決方案源代碼。目的是幫助人們用純 JavaScript 來寫東西,不借助框架和庫,也不使用編譯器和引用。如今你看到的是這系列指南的第 6 篇。完整中文版指南及視頻教程在 從零到壹全棧部落javascript

效果圖

在輸入框中搜索字或者某個詞快速匹配含有這個字或者是詞的詩句。css

涉及特性

  • flex佈局html

  • nth-child奇偶匹配html5

  • linear-gradient顏色漸變java

  • transformgit

  • Fetchgithub

  • Arrayweb

    • filter()正則表達式

    • map()json

    • push()

    • join()

    • ...

  • JavaScript RegExp 對象

    • 字面量語法

    • 建立 RegExp 對象的語法

    • 修飾符ig

    • match()

    • replace()

實現步驟

  • UI佈局

  • 經過Fetch下載數據

  • 數據處理並保存

  • 事件監聽

  • 數據匹配操做

  • 新數據替換展現

佈局篇

  • HTML代碼

<form class="search-form">
    <input type="text" class="search" placeholder="詩人名字,關鍵字">
    <ul class="suggestions">
      <li>輸入詞句,找一首詩</li>
      <li>輸入詞句,找一首詩</li>
      <li>輸入詞句,找一首詩</li>
      <li>輸入詞句,找一首詩</li>
      <li>輸入詞句,找一首詩</li>
    </ul>
  </form>
  • CSS代碼

html {
  box-sizing: border-box;
  margin: 0px;
  background-color: rgb(145, 182, 195);
  font-family: 'Kaiti', 'SimHei', 'Hiragino Sans GB ', 'helvetica neue';
  font-size: 20px;
  font-weight: 200;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  display: flex;
  justify-content: center;
}

.search-form {
  max-width: 700px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

input.search {
  padding: 20px;
  font-family: 'Kaiti', 'helvetica neue';
  margin: 0;
  border: 10px solid #f7f7f7;
  font-size: 40px;
  text-align: center;
  width: 120%;
  outline: 0;
  border-radius: 5px;
  position: relative;
  top: 10px;
  left: 10px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19);
}

.suggestions {
  margin: 0;
  padding: 0;
  position: relative;
  top: 7px;
  width: 100%;
}

.suggestions li {
  background: white;
  list-style: none;
  border-bottom: 1px solid #D8D8D8;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.14);
  margin: 0;
  padding: 20px;
  display: flex;
  flex-direction: column;
  /*align-items: flex-start;*/
}

span.title {
  margin-right: 20px;
  text-align: right;
  color: #7c8e94;
  margin-top: 5px;
}

span.hl {
  color: green;
}



/*偶數匹配*/
.suggestions li:nth-child(even) {
  transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001);
  background: linear-gradient(to bottom, #ffffff 0%, #efefef 100%);
}

/*奇數匹配*/
.suggestions li:nth-child(odd) {
  transform: perspective(100px) rotateX(-3deg) translateY(3px);
  background: linear-gradient(to top, #ffffff 0%, #efefef 100%);
}

經過Fetch下載數據解析而且保存

const endpoint = 'https://gist.githubusercontent.com/liyuechun/f00bb31fb8f46ee0a283a4d182f691b4/raw/3ea4b427917048cdc596b38b67b5ed664605b76d/TangPoetry.json';

const poetrys = [];
fetch(endpoint)
 .then(blob => {
   return blob.json();
 })
 .then(data => {
   poetrys.push(...data);
 });

具體數據請求過程見下圖:

Fetch詳細使用文檔

blob.json()是將數據轉換爲json數據,data爲then函數中轉換完的數據,在這個案例中,data是一個數組。

poetrys.push(...data)這句代碼中的push是往數組裏面新增對象,而...data表明的是將這個data數組中的數據一一的存儲到poetrys數組中。

事件監聽

const search = document.querySelector('.search');
const suggestions = document.querySelector('.suggestions');

search.addEventListener('change', displayMatches);
search.addEventListener('keyup', displayMatches);

獲取searchsuggestions'節點分別對changekeyup事件進行監聽,當輸入框中的內容發生變化或者鍵盤彈起時觸發displayMatches函數更新數據。

數據匹配操做

  • RegExp使用基礎

RegExp參考文檔

  • 項目源碼分析

function findMatches(wordToMatch, poetrys) {
 return poetrys.filter(poet => {
   // 正則找出匹配的詩句
   const regex = new RegExp(wordToMatch, 'gi');
   const author = poet.detail_author.join('');
   //            console.log(author);
   return poet.detail_text.match(regex) || poet.title.match(regex) || author.match(regex);
 });
}

function displayMatches() {
 const matches = findMatches(this.value, poetrys);
 const regex = new RegExp(this.value, 'gi');
 const html = matches.map(poet => {
   // 替換高亮的標籤
   const text = poet.detail_text.replace(regex, `<span class="hl">${ this.value }</span>`);
   const title = poet.title.replace(regex, `<span class="hl">${ this.value }</span>`);
   const detail_author = poet.detail_author[0].replace(regex, `<span class="hl">${ this.value }</span>`);
   // 構造 HTML 值
   return `
 <li>
   <span class="poet">${ text }</span>
   <span class="title">${ title } - ${ detail_author }</span>
 </li>
`;
 }).join('');
 //        console.log(html);
 suggestions.innerHTML = html;
}
  • poetrys.filter會返回帶搜索關鍵字的新數組。

  • const regex = new RegExp(this.value, 'gi'); 表明匹配規則。

  • g:執行全局匹配(查找全部匹配而非在找到第一個匹配後中止)。

  • i:執行對大小寫不敏感的匹配。

  • 上面的這種寫法等價於:"/this.value/gi"。

  • matches.map會返回一個按照新的規則處理完之後的新的數組。

  • title.replace(regex, "新字符串");表示將title字符串中知足 regex 規則的字符串替換成新字符串

源碼下載

Github Source Code

社羣品牌:從零到壹全棧部落

定位:尋找共好,共同窗習,持續輸出全棧技術社羣

業界榮譽:IT界的邏輯思惟

文化:輸出是最好的學習方式

官方公衆號:全棧部落

社羣發起人:春哥(從零到壹創始人,交流微信:liyc1215)

技術交流社區:全棧部落BBS

全棧部落完整系列教程:全棧部落完整電子書學習筆記

關注全棧部落官方公衆號,每晚十點接收系列原創技術推送
相關文章
相關標籤/搜索