整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          小程序中滾動(dòng)條的使用,wx.pageScrollTo

          小程序中滾動(dòng)條的使用,wx.pageScrollTo和<scroll-view>的對(duì)比

          曉程序員,專注微信小程序開發(fā)的程序員!

          前言:近期小程序項(xiàng)目中用到了滾動(dòng)條功能,官方文檔中提供兩種方式。即wx.pageScrollTo滾動(dòng)到page頁(yè)面的指定位置,<scroll-view>組件可以設(shè)置scroll-top或者scroll-left的值,今天探討一下使用哪種方式更合適。

          1、wx.pageScrollTo

          官方文檔地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/scroll.html

          示例代碼:

          wx.pageScrollTo({
          scrollTop: 0
          })

          使用此方式,你需要知道以下幾點(diǎn):

          1、小程序基礎(chǔ)庫(kù)1.4.0之前不支持此方法,這點(diǎn)兒比較坑

          2、小程序中雙擊頂部的textbar,會(huì)默認(rèn)回到頂部

          3、能夠觸發(fā)page的上拉(ReachBottom)和下拉(PullDownRefresh)事件

          4、當(dāng)頁(yè)面中有使用position:fixed布局時(shí),彈出鍵盤時(shí),fixed布局部分會(huì)閃屏

          2、<scroll-view>

          小程序中另一種實(shí)現(xiàn)滾動(dòng)條的方式,是使用scroll-view組件。官方文檔:https://mp.weixin.qq.com/debug/wxadoc/dev/component/scroll-view.html

          詳細(xì)的參數(shù),請(qǐng)仔細(xì)查看官方文檔~

          示例代碼:

          <scroll-view class="scroll-view" scroll-y style="height: 500px;" scroll-top="{{scrollTop}}">
           <view id="green" class="bc_green"></view>
           <view id="red" class="bc_red"></view>
           <view id="yellow" class="bc_yellow"></view>
           <view id="blue" class="bc_blue"></view>
          </scroll-view>

          使scroll-view組件方式,你需要知道以下幾點(diǎn):

          1、縱向滾動(dòng)(scroll-y)時(shí),必須設(shè)置height值,并且不能使用css中的calc來(lái)計(jì)算,scroll-top值才會(huì)生效

          2、小程序中雙擊頂部的textbar,無(wú)法回到頂部

          3、無(wú)法觸發(fā)page的上拉(ReachBottom)和下拉(PullDownRefresh)事件

          4、當(dāng)頁(yè)面中position:fixed布局不受影響

          往期回顧

          1.微信小程序具備哪些API能力,你都清楚嘛?

          2.小程序中tabBar的使用

          3.小程序中picker的使用|日期、時(shí)間、省市區(qū)聯(lián)動(dòng)都可以用它實(shí)現(xiàn)

          4.swiper組件添加左右箭頭

          5.如何跳出小程序五級(jí)頁(yè)面的限制

          知曉程序員,一個(gè)專注于微信小程序開發(fā)的程序員~

          如果對(duì)小程序技術(shù)感興趣,歡迎關(guān)注知曉程序員哦,歡迎討論問題 & 一起探討小程序人生~~

          載說(shuō)明:原創(chuàng)不易,未經(jīng)授權(quán),謝絕任何形式的轉(zhuǎn)載

          在當(dāng)今充滿活力的網(wǎng)絡(luò)開發(fā)領(lǐng)域中,實(shí)現(xiàn)強(qiáng)大的搜索功能是一個(gè)關(guān)鍵特性,可以極大地增強(qiáng)用戶體驗(yàn),并使瀏覽大型數(shù)據(jù)集變得輕松自如。如果您想要為您的網(wǎng)站或網(wǎng)絡(luò)應(yīng)用程序添加實(shí)時(shí)搜索功能,那么您來(lái)對(duì)地方了。本篇全面的文章將探討使用JavaScript實(shí)現(xiàn)實(shí)時(shí)搜索功能的方方面面。

          無(wú)論您是經(jīng)驗(yàn)豐富的開發(fā)人員還是剛開始編碼之旅的新手,本文旨在為您提供一般編碼知識(shí)和工具,以便將實(shí)時(shí)搜索功能融入到您的項(xiàng)目中。通過(guò)本指南的學(xué)習(xí),您將對(duì)相關(guān)概念和技術(shù)有扎實(shí)的理解,從而能夠創(chuàng)建響應(yīng)式和交互式的搜索功能,實(shí)現(xiàn)用戶輸入時(shí)動(dòng)態(tài)更新的效果。

          為了有效地跟隨本指南,建議您對(duì)HTML、CSS和JavaScript的基本知識(shí)有扎實(shí)的理解。熟悉DOM操作和事件處理將有助于我們深入了解實(shí)現(xiàn)細(xì)節(jié)。然而,即使您對(duì)JavaScript或Web開發(fā)相對(duì)較新,本指南的結(jié)構(gòu)也旨在提供清晰的解釋和逐步的說(shuō)明,使其適用于不同技能水平的學(xué)習(xí)者。

          現(xiàn)在,為了更好地理解這個(gè)功能的重要性和使用方法,我們將創(chuàng)建一個(gè)非常基本的項(xiàng)目作為示例;更具體地說(shuō),一個(gè)如下所示的電影應(yīng)用程序:

          您可以在這里查看實(shí)時(shí)實(shí)施情況。

          https://search-movies-live.netlify.app/

          在這個(gè)項(xiàng)目中,我們將利用實(shí)時(shí)搜索功能來(lái)搜索電影數(shù)據(jù)庫(kù)中的電影列表。我知道你迫不及待地想要開始了,我們馬上就會(huì)開始。但首先,讓我們更多地了解一下實(shí)時(shí)搜索功能及其重要性。

          實(shí)時(shí)搜索功能的重要性

          在當(dāng)今數(shù)字化的環(huán)境中,實(shí)時(shí)搜索功能變得至關(guān)重要,滿足了高效信息檢索的需求,提升了整體用戶體驗(yàn)。通過(guò)在用戶輸入時(shí)實(shí)時(shí)更新搜索結(jié)果,實(shí)時(shí)搜索提供即時(shí)反饋,便于快速獲取相關(guān)信息。這種動(dòng)態(tài)交互式的搜索功能帶來(lái)了許多好處,使用戶和網(wǎng)站所有者受益。

          • 改進(jìn)的用戶體驗(yàn):實(shí)時(shí)搜索通過(guò)提供無(wú)縫和直觀的搜索過(guò)程顯著提升了用戶體驗(yàn)。當(dāng)用戶開始輸入查詢時(shí),搜索結(jié)果會(huì)實(shí)時(shí)更新,提供即時(shí)反饋,消除了手動(dòng)提交或頁(yè)面刷新的需求。這種互動(dòng)性節(jié)省了用戶寶貴的時(shí)間和精力,從而實(shí)現(xiàn)了更高效和令人滿意的搜索體驗(yàn)。
          • 更快的信息檢索:通過(guò)實(shí)時(shí)搜索,用戶可以快速找到所需的信息,無(wú)需瀏覽多個(gè)頁(yè)面或等待搜索結(jié)果加載。隨著用戶的輸入,搜索結(jié)果立即縮小范圍,顯示相關(guān)建議,無(wú)需輸入完整的搜索查詢。這種速度和響應(yīng)能夠使用戶在傳統(tǒng)搜索方法所需時(shí)間的一小部分內(nèi)找到他們想要的內(nèi)容。
          • 增加參與度和轉(zhuǎn)化率:實(shí)時(shí)搜索的無(wú)縫和響應(yīng)性特性鼓勵(lì)用戶更積極地與網(wǎng)站或網(wǎng)絡(luò)應(yīng)用程序互動(dòng)。提供即時(shí)反饋和相關(guān)建議可以保持用戶的參與度,減少跳出率和沮喪感的可能性。這種增加的參與度可以提高轉(zhuǎn)化率,因?yàn)橛脩舾锌赡苓M(jìn)一步探索網(wǎng)站并將他們的搜索意圖轉(zhuǎn)化為行動(dòng)。
          • 增強(qiáng)的過(guò)濾和細(xì)化功能:實(shí)時(shí)搜索功能通常包括額外的功能,如過(guò)濾器、建議和自動(dòng)完成選項(xiàng)。這些功能幫助用戶細(xì)化搜索并縮小結(jié)果范圍,使他們能夠找到他們想要的內(nèi)容。通過(guò)提供這些工具,實(shí)時(shí)搜索不僅改善了搜索體驗(yàn),還幫助用戶發(fā)現(xiàn)可能一開始沒有考慮到的相關(guān)內(nèi)容或產(chǎn)品。
          • 網(wǎng)站所有者的寶貴見解:實(shí)時(shí)搜索功能可以為用戶行為和偏好提供寶貴的見解。通過(guò)分析搜索查詢和模式,網(wǎng)站所有者可以更好地了解用戶的需求,識(shí)別流行趨勢(shì)或話題,并在內(nèi)容創(chuàng)作、產(chǎn)品提供或用戶界面改進(jìn)方面做出明智決策。這些見解使網(wǎng)站所有者能夠根據(jù)用戶需求量身定制自己的產(chǎn)品,從而提高客戶滿意度和業(yè)務(wù)增長(zhǎng)。

          設(shè)置HTML結(jié)構(gòu)

          既然我們已經(jīng)完全了解了實(shí)時(shí)搜索功能以及它的重要性,那么讓我們深入探討一下如何在您自己的項(xiàng)目中實(shí)現(xiàn)這個(gè)功能。

          首先,讓我們建立項(xiàng)目的結(jié)構(gòu)。對(duì)于這個(gè)項(xiàng)目,我們只需要三個(gè)文件,即HTML、CSS和JavaScript文件。

          現(xiàn)在讓我們開始設(shè)置項(xiàng)目的HTML結(jié)構(gòu):在HTML文件中,我們首先需要包含我們的標(biāo)準(zhǔn)HTML樣板,包括鏈接和腳本到我們的CSS和JS文件中:

          <!doctype html>
          <html lang="en">
           <head>
             <meta charset="UTF-8" />
             <meta name="viewport" content="width=device-width, initial-scale=1.0" />
             <link rel="stylesheet" href="./live-search.css" />
             <title> </title>
           </head>
           <body>
             <script src="./live-search.js"></script>
           </body>
          </html>

          現(xiàn)在在 body 標(biāo)簽中,我們包含了 header 和 main 語(yǔ)義標(biāo)簽。在 header 標(biāo)簽內(nèi),我們?cè)O(shè)置了項(xiàng)目的標(biāo)題部分,這里只包括應(yīng)用程序的名稱和一個(gè)視頻圖標(biāo)。

          <header>
           <ion-icon name="videocam"></ion-icon>
           <h1>Search Movies</h1>
          </header>

          在我們繼續(xù)講解 main 標(biāo)簽之前,在 body 標(biāo)簽的末尾,讓我們包含所需的 script 標(biāo)簽,以便能夠使用這些圖標(biāo):

          <script
           type="module"
           src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"
          ></script>
          <script
           nomodule
           src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"
          ></script>

          您可以在Ionicons網(wǎng)站上找到這些圖標(biāo)。

          https://ionic.io/ionicons

          現(xiàn)在,在 main 標(biāo)簽內(nèi),我們將包含我們的第一個(gè) div 標(biāo)簽,這將是我們的搜索欄容器,在其中,我們放置我們的搜索輸入標(biāo)簽和一個(gè)搜索圖標(biāo):

          <div id="search-container">
           <ion-icon name="search-outline"></ion-icon>
           <input type="search" id="search-bar" placeholder="Search movies..." />
          </div>

          然后,我們將在這個(gè)“div”下面創(chuàng)建另一個(gè) div 標(biāo)簽。這將包含所有電影數(shù)據(jù)的結(jié)果:

          <div id="results-container"></div>

          我們暫時(shí)將其留空,因?yàn)槠鋬?nèi)容將在JavaScript部分生成。

          最后,在 main 標(biāo)簽中,我們將包含一個(gè) p 標(biāo)簽。這個(gè)標(biāo)簽只是為了在稍后向用戶顯示錯(cuò)誤或空消息的響應(yīng)。

          <p id="movie-unavailable-txt"></p>

          這就是HTML文件的全部?jī)?nèi)容,整體代碼應(yīng)該是這樣的:

          <!doctype html>
          <html lang="en">
           <head>
             <meta charset="UTF-8" />
             <meta http-equiv="X-UA-Compatible" content="IE=edge" />
             <meta name="viewport" content="width=device-width, initial-scale=1.0" />
             <link rel="stylesheet" href="./live-search.css" />
             <title>Live Search Functionality</title>
           </head>
           <body>
             <header>
               <ion-icon name="videocam"></ion-icon>
               <h1>Search Movies</h1>
             </header>
          
             <main>
               <div id="search-container">
                 <ion-icon name="search-outline"></ion-icon>
                 <input type="search" id="search-bar" placeholder="Search movies..." />
               </div>
          
               <div id="results-container"></div>
          
               <p id="movie-unavailable-txt"></p>
             </main>
          
             <script src="./live-search.js"></script>
             <script
               type="module"
               src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"
             ></script>
             <script
               nomodule
               src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"
             ></script>
           </body>
          </html>

          既然我們已經(jīng)完成了項(xiàng)目的HTML結(jié)構(gòu)的實(shí)現(xiàn),那么讓我們給頁(yè)面添加一些樣式。

          為頁(yè)面添加樣式

          在這個(gè)部分,我們將為頁(yè)面的各個(gè)部分添加基本的樣式。所以讓我們開始吧。首先,讓我們?yōu)轫?yè)面的整體部分添加一些常規(guī)樣式:

          html{
           scroll-behavior: smooth;
           background-color: #111;
           color: whitesmoke;
          }
          
          *{
           margin: 0;
           padding: 0;
           box-sizing: border-box;
          }
          

          現(xiàn)在讓我們?yōu)轭^部部分及其內(nèi)容添加一些樣式:

          header{
           display: flex;
           justify-content: center;
           padding: 25px;
           letter-spacing: 2px;
           position: sticky;
           top: 0%;
           z-index: 2;
           border-bottom: 2px solid ;
           background-color: black;
           text-shadow: 3px 3px 5px #fd1d6b;   
           box-shadow: 10px 10px 20px -10px #fd1d6b; 
          }
          
          header > ion-icon{
           color:#fd1d6b;
           font-size: 60px;
           position: absolute;
           left: 5%;
          }

          接下來(lái),我們開始對(duì)搜索容器及其內(nèi)容進(jìn)行樣式設(shè)置:

          #search-container{
           display: flex;
           justify-content: center;
           padding: 20px;
           margin-bottom: 20px;
           position: sticky;
           top: 100px;
          }
          
          #search-bar{
           border: none;
           width: 60%;
           padding: 15px;
           padding-left: 40px;
           border-radius: 15px;
           font-size: 15px;
          }
          
          #search-container>ion-icon{
           color: gray;
           position: relative;
           left: 30px;
           top: 13px;
           z-index: 3;
           font-size: 19px;
          }

          之后,我們繼續(xù)設(shè)計(jì)將來(lái)從電影數(shù)據(jù)庫(kù)中獲取的所有電影的 results-container 的樣式

          #results-container{
           border-right: 5px solid #fd1d6b;
           border-left: 5px solid #fd1d6b;     
           border-radius: 25px;
           display: flex;
           justify-content: center;
           flex-wrap: wrap;
           width: 90vw;
          }

          接下來(lái),我們?cè)?movie-unavailable-txt 中添加樣式,同時(shí)將 display 設(shè)置為 none ,因?yàn)槲覀儠簳r(shí)不希望它可見

          #movie-unavailable-txt{
           text-align: center;
           letter-spacing: 2px;
           display: none;
           margin-top: 15%;
           text-shadow: 3px 3px 5px #fd1d6b;
          }
          

          接下來(lái),我們將為一些尚未聲明但將通過(guò)JavaScript創(chuàng)建的元素添加一些樣式。這是電影卡片,將顯示電影的詳細(xì)信息,包括電影圖片和標(biāo)題:

          .movie-cards{
           padding: 25px;
           max-width: 250px;
           border-radius: 15px;
           display: grid;
           place-items: center;
           box-shadow: 1px 1px 20px -1px #fd1d6b ;
           margin: 50px;
          }
          
          .title{
           margin: 20px auto;
           text-align: center;
           font-size: 1.2rem;
           text-shadow: 3px 3px 5px #fd1d6b;  
          }
          
          .date{
           margin-top: 15px;
           font-size: 0.8rem;
           text-shadow: 3px 3px 5px #fd1d6b;  
          }
          
          .movie-image{
           width: 90%;
           max-width: 400px;
           object-fit: contain;
           border-radius: 5px;
          }

          既然我們已經(jīng)完成了頁(yè)面的樣式,那么讓我們繼續(xù)進(jìn)行最有趣和最重要的部分,即Javascript的實(shí)現(xiàn)。

          向電影數(shù)據(jù)庫(kù)API發(fā)送異步搜索請(qǐng)求

          在本節(jié)中,我們將調(diào)用我們選擇的電影數(shù)據(jù)庫(kù)API來(lái)填充我們的頁(yè)面,展示各種電影。在這種情況下,我將使用RapidAPI Hub中的IMDb Top 100 Movies免費(fèi)電影API。在API頁(yè)面中,我們選擇要使用的特定數(shù)據(jù),然后復(fù)制頁(yè)面右側(cè)提供的javascript(fetch)代碼,如下所示:

          https://rapidapi.com/rapihub-rapihub-default/api/imdb-top-100-movies

          首先,在您使用API之前,請(qǐng)先訂閱它(無(wú)需信用卡),以便為您生成一個(gè)API密鑰。您可以在API的定價(jià)頁(yè)面上進(jìn)行訂閱。

          繼續(xù),我們進(jìn)入我們的空的JavaScript文件,并將我們復(fù)制的代碼粘貼進(jìn)去:

          const url="https://imdb-top-100-movies.p.rapidapi.com/";
          const options={
           method: "GET",
           headers: {
             "X-RapidAPI-Key": "YOUR GENERATED API KEY",
             "X-RapidAPI-Host": "imdb-top-100-movies.p.rapidapi.com",
           },
          };
          
          try {
           const response=await fetch(url, options);
           const result=await response.text();
           console.log(result);
          } catch (error) {
           console.error(error);
          }

          既然我們已經(jīng)將電影數(shù)據(jù)庫(kù)的API引入到我們的項(xiàng)目中,我們可以使用它的數(shù)據(jù)了。接下來(lái),我們將聲明一些我們需要的變量,并將它們放在我們復(fù)制的代碼中 try 塊的上方。

          const searchBar=document.getElementById("search-bar");
          const resultsContainer=document.getElementById("results-container");
          const movieUnavailableTxt=document.getElementById("movie-unavailable-txt");
          let movieList;
          let searchValue;
          let searchedMovies;

          我們正在接近剛剛創(chuàng)建的這些變量的目的,堅(jiān)持住。

          接下來(lái),我們對(duì)復(fù)制的代碼中的 try 塊進(jìn)行一些更改,因?yàn)槲覀兿M麑⑵渑c我們的項(xiàng)目完全集成。所以首先,我們需要?jiǎng)?chuàng)建一個(gè)異步函數(shù):

          const fetchMovies=async ()=> {
           // try catch block goes in here.
          };

          在這個(gè)函數(shù)內(nèi)部,我們將放置從我們復(fù)制的代碼中的整個(gè) try catch 塊,以便我們可以進(jìn)行異步API調(diào)用。

          在 try 塊內(nèi),我們將刪除 console.log(result) 行,并將 result 變量更改為先前聲明的 movieList 變量,并將同一行中的 response.text() 更改為 response.json() 。這樣,我們從API調(diào)用中接收到的數(shù)據(jù)將以 JSON 格式呈現(xiàn),這是我們所需的。因此,該行現(xiàn)在應(yīng)該是這樣的

          movieList=await response.json();

          現(xiàn)在我們已經(jīng)成功從API中獲取了電影并返回了我們的數(shù)據(jù)集,我們需要將這些數(shù)據(jù)填充到我們的頁(yè)面中。為此,我們將調(diào)用 renderMovies() 函數(shù),并將參數(shù)設(shè)置為從API調(diào)用中獲取的數(shù)據(jù)。不用擔(dān)心,我們很快就會(huì)創(chuàng)建這個(gè)函數(shù):

          renderMovies(movieList);

          現(xiàn)在讓我們創(chuàng)建 renderMovies 函數(shù),這個(gè)函數(shù)剛剛在 fetchMovies() 函數(shù)中調(diào)用過(guò),這個(gè)函數(shù)將用于創(chuàng)建動(dòng)態(tài)電影卡片模板,我們之前在CSS文件中設(shè)置了樣式,模板中的每個(gè)元素的內(nèi)容都將設(shè)置為從API獲取的數(shù)據(jù),這樣我們就可以使用相同的模板渲染不同的電影。然后,我們將把電影卡片放在 resultsContainer 元素中。每次調(diào)用函數(shù)時(shí),我們需要清除 resultsContainer ,并將 moviesUnavailableTxt 設(shè)置為 display="none" ,因?yàn)槲覀兿M阡秩倦娪暗巾?yè)面時(shí)文本不可見,同時(shí)清除 moviesReturnedOnSearch 數(shù)組,然后將從搜索輸入字段返回的新數(shù)據(jù)設(shè)置到其中。

          const renderMovies=(movies)=> {
           resultsContainer.innerHTML=""; // Clear the existing movies
           movieUnavailableTxt.style.display="none"; // Hide the "No movies found" message
           moviesReturnedOnSearch=[]; // Clear the movies returned on search array
          
           movies.forEach((movie)=> {
             resultsContainer.innerHTML +=`
               <div class="movie-cards">
                 <img src="${movie.image}" alt="movie image" class="movie-image" />
                 <h2 class="title">${movie.title}</h2>
                 <p class="plot">${movie.description}</p>
                 <p class="date">${movie.year}</p>
               </div>
             `;
          
             moviesReturnedOnSearch.push(movie); // Add the movies that are a result to the search input value
           });
          };

          捕捉用戶輸入并實(shí)時(shí)顯示電影搜索結(jié)果

          現(xiàn)在我們已經(jīng)將所有電影數(shù)據(jù)加載到我們的頁(yè)面上,接下來(lái)是真正有趣的部分,我們要實(shí)現(xiàn)實(shí)時(shí)搜索功能,所以,不浪費(fèi)時(shí)間,讓我們開始吧。

          為了捕獲用戶輸入,我們將使用 input 事件監(jiān)聽器,并將其鏈接到 searchBar 元素。我們使用這個(gè)特定的事件監(jiān)聽器,因?yàn)樗梢圆东@搜索框內(nèi)的每一個(gè)活動(dòng),包括輸入、清除和粘貼,這正是我們想要的。所以讓我們繼續(xù)創(chuàng)建它:

          searchBar.addEventListener("input", (event)=> {
           // live functionality code
          });

          好的,現(xiàn)在我們已經(jīng)將事件監(jiān)聽器鏈接到搜索欄,以便監(jiān)聽用戶的任何輸入。在第二個(gè)參數(shù)中,我們添加了事件處理程序,這是每當(dāng)搜索欄有輸入時(shí)將被調(diào)用的函數(shù)。現(xiàn)在,在該函數(shù)內(nèi)部,我們將編寫處理實(shí)時(shí)搜索的代碼。

          在搜索功能中,我們需要做的第一件事是編輯從用戶那里獲取到的輸入值,并將其轉(zhuǎn)換為全小寫,同時(shí)去除任何不必要的空格:

          searchValue=event.target.value.trim().toLowerCase();

          在那之后,我們繼續(xù)根據(jù)用戶的搜索輸入,通過(guò)檢查用戶輸入的電影標(biāo)題是否包含在 movieList 數(shù)據(jù)中的任何電影標(biāo)題中,并將電影標(biāo)題設(shè)置為小寫以與用戶輸入匹配,來(lái)在頁(yè)面上按標(biāo)題篩選電影

          const filteredMovies=movieList.filter( (movie)=> movie.title.toLowerCase().includes(searchValue) );

          接下來(lái),我們將通過(guò)再次調(diào)用 renderMovies() 函數(shù),并將參數(shù)設(shè)置為 filtered Movies 變量的值,來(lái)顯示與用戶在搜索欄中輸入的字符匹配的電影標(biāo)題的實(shí)時(shí)搜索結(jié)果。

          renderMovies(filteredMovies);

          通過(guò)調(diào)用此函數(shù),它僅將與搜索欄中鍵入的字符匹配的電影渲染到頁(yè)面上,使用函數(shù)中提供的電影卡片模板,同時(shí)將每個(gè)匹配的電影添加到 moviesReturnedOnSearch 數(shù)組中,以便我們可以跟蹤每個(gè)字符輸入的匹配搜索值的電影數(shù)量。在處理空響應(yīng)錯(cuò)誤時(shí),這將非常有用,現(xiàn)在我們將進(jìn)入這個(gè)部分。

          處理空或錯(cuò)誤響應(yīng)

          在任何應(yīng)用程序中,有效處理空或錯(cuò)誤的響應(yīng)至關(guān)重要。在這種情況下,這些情景可能發(fā)生在搜索查詢沒有結(jié)果或API請(qǐng)求存在問題時(shí)。

          處理錯(cuò)誤或空響應(yīng)時(shí),向用戶提供清晰的反饋是至關(guān)重要的。話雖如此,由于這是一個(gè)相對(duì)簡(jiǎn)單的應(yīng)用程序,我們不必過(guò)多擔(dān)心錯(cuò)誤,因?yàn)槲覀冎恍枰幚碛葾PI引起的錯(cuò)誤。例如,API服務(wù)可能暫時(shí)不可用,或者應(yīng)用程序可能剛剛超過(guò)了請(qǐng)求限制。為了處理這個(gè)錯(cuò)誤,我們只需要將 movieUnavailableTxt 元素的 display 設(shè)置為 block ,并將 innerHTML 設(shè)置為向用戶顯示錯(cuò)誤消息,并將其放置在 fetchMovies() 函數(shù)的 catch 塊中。因此,現(xiàn)在 catch 塊的代碼如下所示:

          catch (error) {
           movieUnavailableTxt.innerHTML='An error occurred while fetching movies. <br /> Please try again later.';
           movieUnavailableTxt.style.display="block";
           console.error(error);
          }

          現(xiàn)在我們已經(jīng)處理完錯(cuò)誤響應(yīng),接下來(lái)我們要處理空響應(yīng)。如果用戶搜索的電影與頁(yè)面上的任何電影都不匹配,我們需要向用戶提示所搜索的電影不可用。為了做到這一點(diǎn),首先我們需要檢查之前聲明的 moviesReturnedOnSearch 數(shù)組的內(nèi)容,如果數(shù)組的長(zhǎng)度小于或等于0,我們將設(shè)置 movieUnavailableTxt 元素的 display 為 block ,并將 innerHTML 設(shè)置為空響應(yīng)消息,如下所示:

          if (moviesReturnedOnSearch.length <=0) {
           movieUnavailableTxt.innerHTML="OOPS! <br/><br/> Movie not available";
           movieUnavailableTxt.style.display="block"; // Show the "No movies found" message if no movies match the search
          }

          我們將把這個(gè) if 塊放在 searchBar 事件處理程序的閉合括號(hào)之前。

          通過(guò)緩存提高搜索性能

          在使用API實(shí)現(xiàn)實(shí)時(shí)搜索功能時(shí),提高性能的一種有效技術(shù)是緩存。緩存涉及存儲(chǔ)先前獲取的搜索結(jié)果,并在再次請(qǐng)求相同的搜索查詢時(shí)重復(fù)使用它們。這可以顯著減少API調(diào)用的次數(shù),有助于防止超過(guò)API的請(qǐng)求限制,并改善搜索功能的響應(yīng)速度以及網(wǎng)站的加載時(shí)間。

          要在我們的項(xiàng)目中實(shí)現(xiàn)緩存,首先,我們需要確定哪些項(xiàng)目需要被緩存,而在這種情況下,那將是 movieList 變量的值,它是我們從 fetch API請(qǐng)求中得到的 JSON 格式的數(shù)據(jù)。通過(guò)緩存這個(gè)項(xiàng)目,我們將能夠在頁(yè)面重新加載時(shí)使用API的數(shù)據(jù),而無(wú)需進(jìn)行額外的 fetch 請(qǐng)求。但是對(duì)于這個(gè)項(xiàng)目,我們將為我們的緩存數(shù)據(jù)設(shè)置一個(gè)過(guò)期時(shí)間,為6小時(shí),這意味著頁(yè)面每6小時(shí)只會(huì)進(jìn)行一次API請(qǐng)求,而不是在每次頁(yè)面重新加載時(shí)都進(jìn)行請(qǐng)求。這樣做是為了保持頁(yè)面的數(shù)據(jù)新鮮和最新,同時(shí)將API請(qǐng)求保持在最低限度。

          回到我們的代碼中,現(xiàn)在我們需要將數(shù)據(jù)存儲(chǔ)在瀏覽器的本地存儲(chǔ)中,但為了做到這一點(diǎn),我們需要首先將其轉(zhuǎn)換為一個(gè) string ,并設(shè)置一個(gè)鍵名,用于在本地存儲(chǔ)中標(biāo)識(shí)數(shù)據(jù)。讓我們將其設(shè)置為 movieData ,如下所示:

          localStorage.setItem("moviedata", JSON.stringify(movieList));

          接下來(lái)我們需要將當(dāng)前日期和時(shí)間存儲(chǔ)在本地存儲(chǔ)中:

          localStorage.setItem("cacheTimestamp", Date.now());

          這將當(dāng)前日期和時(shí)間以毫秒為單位存儲(chǔ),鍵名為 cacheTimeStamp 。

          我們將把這兩行代碼放在 try 塊的 fetchMovies() 函數(shù)中,就在 movieList 變量的下方。

          接下來(lái),在 fetchMovies() 函數(shù)之外,緊接著 renderMovies() 函數(shù)的下方,我們將把緩存數(shù)據(jù)的過(guò)期時(shí)間設(shè)置為6小時(shí)(以毫秒為單位)

          const expirationDuration=21600000; // 6 hours in milliseconds

          之后,我們需要取回之前在本地存儲(chǔ)中設(shè)置的 cacheTimestamp

          const cacheTimestamp=localStorage.getItem("cacheTimestamp");

          現(xiàn)在,我們將檢查緩存數(shù)據(jù)是否已過(guò)期或不可用,這意味著它尚未被存儲(chǔ)。如果是這種情況,我們將通過(guò)調(diào)用 fetch 函數(shù)向API發(fā)出新的請(qǐng)求。另一方面,如果緩存數(shù)據(jù)存在且尚未過(guò)期,我們將使用它來(lái)渲染頁(yè)面上的電影,而不是再次發(fā)出新的 fetch 請(qǐng)求。我們通過(guò)檢索緩存的電影數(shù)據(jù)并將其解析回 JSON 格式來(lái)使用,然后將參數(shù)設(shè)置為從緩存中獲取的數(shù)據(jù),調(diào)用 render 函數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn)。

          // Check if cache has expired or data is not available
          if (
           !cacheTimestamp ||
           Date.now() - parseInt(cacheTimestamp) > expirationDuration
          ) {
           // Cache expired or data not available, fetch movies again
           fetchMovies();
          } else {
           // Use cached movie data
           movieList=JSON.parse(localStorage.getItem("moviedata"));
           renderMovies(movieList);
          }

          在 if 語(yǔ)句中, !cacheTimestamp 檢查 cacheTimestamp 變量是否為假值,意味著它可以是 null 、 undefined 、0、 false 或空字符串。如果 cacheTimestamp 為假,表示沒有存儲(chǔ)現(xiàn)有緩存時(shí)間戳。 Date.now() - parseInt(cacheTimestamp) 計(jì)算當(dāng)前時(shí)間戳與解析的 cacheTimestamp 的整數(shù)值之間的時(shí)間差。簡(jiǎn)單來(lái)說(shuō),這就是說(shuō):“當(dāng)前時(shí)間的值減去我們之前存儲(chǔ)在緩存中的時(shí)間的值,是否大于我們?cè)O(shè)置的過(guò)期時(shí)間?如果是,就從API中重新獲取電影數(shù)據(jù);如果不是,就使用緩存的數(shù)據(jù)。”

          就是這樣,這就是我們?nèi)绾螌?shù)據(jù)緩存起來(lái)以便重復(fù)使用,而不是在每次用戶輸入或每次頁(yè)面重新加載時(shí)發(fā)起請(qǐng)求。正如你所看到的,這將極大地優(yōu)化應(yīng)用程序的性能,因?yàn)樗梢苑乐褂捎诰W(wǎng)絡(luò)慢而導(dǎo)致的電影渲染緩慢。

          我們已經(jīng)完成了我們的小電影應(yīng)用程序中展示實(shí)時(shí)搜索功能的所有特性的實(shí)現(xiàn)。以下是該應(yīng)用程序的整體JavaScript代碼:

          const url="https://imdb-top-100-movies.p.rapidapi.com/";
          const options={
           method: "GET",
           headers: {
             "X-RapidAPI-Key": "Your Generated API Key",
             "X-RapidAPI-Host": "imdb-top-100-movies.p.rapidapi.com",
           },
          };
          
          const searchBar=document.getElementById("search-bar");
          const resultsContainer=document.getElementById("results-container");
          const movieUnavailableTxt=document.getElementById("movie-unavailable-txt");
          let movieList;
          let searchValue;
          let moviesReturnedOnSearch;
          
          // Function to fetch movies from the API
          const fetchMovies=async ()=> {
           try {
             const response=await fetch(url, options);
             movieList=await response.json();
          
             // Storing the Movie Data in browser storage
             localStorage.setItem("moviedata", JSON.stringify(movieList));
             localStorage.setItem("cacheTimestamp", Date.now()); // Update cache timestamp
          
             // Render the movies on the page
             renderMovies(movieList);
           } catch (error) {
             movieUnavailableTxt.innerHTML="An error occurred while fetching movies. <br /> Please try again later.";
             movieUnavailableTxt.style.display="block";
             console.error(error);
           }
          };
          
          // Function to render movies on the page
          const renderMovies=(movies)=> {
           resultsContainer.innerHTML=""; // Clear the existing movies
           movieUnavailableTxt.style.display="none"; // Hide the "No movies found" message
           moviesReturnedOnSearch=[]; // Clear the movies returned on search array
          
           movies.forEach((movie)=> {
             resultsContainer.innerHTML +=`
               <div class="movie-cards">
                 <img src="${movie.image}" alt="movie image" class="movie-image" />
                 <h2 class="title">${movie.title}</h2>
                 <p class="plot">${movie.description}</p>
                 <p class="date">${movie.year}</p>
               </div>
             `;
          
             moviesReturnedOnSearch.push(movie); // Add the movies that are a result to the search input value
           });
          };
          
          const cacheTimestamp=localStorage.getItem("cacheTimestamp");
          const expirationDuration=21600000; // 6 hours in milliseconds
          
          // Check if cache has expired or data is not available
          if (
           !cacheTimestamp ||
           Date.now() - parseInt(cacheTimestamp) > expirationDuration
          ) {
           // Cache expired or data not available, fetch movies again
           fetchMovies();
          } else {
           // Use cached movie data
           movieList=JSON.parse(localStorage.getItem("moviedata"));
           renderMovies(movieList);
          }
          
          // Event listener and handler for search bar input
          searchBar.addEventListener("input", (event)=> {
           searchValue=event.target.value.trim().toLowerCase();
          
           // Filter movies based on search input
           const filteredMovies=movieList.filter((movie)=>
             movie.title.toLowerCase().includes(searchValue),
           );
          
           // Render the filtered movies on the page
           renderMovies(filteredMovies);
          
           if (moviesReturnedOnSearch.length <=0) {
             movieUnavailableTxt.style.display="block"; // Show the "No movies found" message if no movies match the search
           }
          });

          結(jié)論

          在本指南中,我們探討了使用API在JavaScript中實(shí)現(xiàn)實(shí)時(shí)搜索功能的方法。按照所述步驟,您可以創(chuàng)建一個(gè)動(dòng)態(tài)搜索體驗(yàn),當(dāng)用戶在搜索欄中輸入時(shí),可以提供實(shí)時(shí)結(jié)果。

          通過(guò)在您的網(wǎng)站上實(shí)現(xiàn)實(shí)時(shí)搜索功能,您可以增強(qiáng)用戶參與度,提高您的網(wǎng)站或應(yīng)用程序的可用性。用戶將欣賞能夠快速方便地找到相關(guān)信息,而無(wú)需重新加載頁(yè)面。

          通過(guò)這個(gè)指南所獲得的知識(shí),您已經(jīng)具備了在JavaScript中有效實(shí)現(xiàn)實(shí)時(shí)搜索功能的能力。擁抱動(dòng)態(tài)搜索的力量,創(chuàng)造一個(gè)無(wú)縫的用戶體驗(yàn),給人留下深刻的印象。

          由于文章內(nèi)容篇幅有限,今天的內(nèi)容就分享到這里,文章結(jié)尾,我想提醒您,文章的創(chuàng)作不易,如果您喜歡我的分享,請(qǐng)別忘了點(diǎn)贊和轉(zhuǎn)發(fā),讓更多有需要的人看到。同時(shí),如果您想獲取更多前端技術(shù)的知識(shí),歡迎關(guān)注我,您的支持將是我分享最大的動(dòng)力。我會(huì)持續(xù)輸出更多內(nèi)容,敬請(qǐng)期待。

          <script src="https://lf6-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>

          之前遇見一個(gè)場(chǎng)景,點(diǎn)擊內(nèi)容區(qū)某個(gè)按鈕之后定位到視口區(qū)域以外的一個(gè)元素。有一種實(shí)現(xiàn)方式是使用a標(biāo)簽的錨點(diǎn)來(lái)實(shí)現(xiàn),但滾動(dòng)方式過(guò)于生硬。如果想平滑過(guò)渡到目標(biāo)元素,就需要js里一個(gè)api來(lái)實(shí)現(xiàn)了,以下是兩個(gè)點(diǎn)需要介紹下:

          1. 獲取目標(biāo)元素位置信息
          • 可以使用 ele.getBoundingClientRect
          • 可以使用 ele.offsetTop/ele.offsetLeft
          1. window.scrollTo(opts)參數(shù)
          • opts.top
          • opts.left
          • opts.behavior 過(guò)渡行為

          完整的demo


          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>scroll</title>
            
          </head>
          <body>
            <div>
              <button>滾動(dòng)到底部</button>
              <!-- 錨點(diǎn)定位 -->
              <!-- <a href="#footer">滾動(dòng)到底部</a> -->
              <div style="height: 2000px; background-color: #ccc;margin-bottom: 40px;"></div>
              <div style="line-height: 100px;" id="footer">我是底部區(qū)域</div>
            </div>
            <script>
              const btn=document.querySelector('button')
              const footer=document.querySelector('#footer')
              btn.onclick=function(){
                // 獲取元素的位置信息
                // 可以使用getBoundingClientRect
                // 也可以使用footer.offsetTop
                const opts=footer.getBoundingClientRect()
                console.log('/scroll.html [18]--1','opts',opts,footer.offsetTop);
                window.scrollTo(
                  {
                    left:0,
                    top:opts.top,// 滾動(dòng)到指定元素的頂部
                    // top:footer.offsetTop,// 滾動(dòng)到指定元素的頂部
                    behavior: 'smooth',// 平滑滾動(dòng)
                    // behavior: 'auto',// 默認(rèn)值,立即跳轉(zhuǎn)
                    // behavior: 'instant'// 立即跳轉(zhuǎn)
                  }
                )
              }
            </script>
            </div>
          </body>
          </html>


          ps: getBoundingClientRect 元素位置信息


          getBoundingClientRect


          主站蜘蛛池模板: 在线精品动漫一区二区无广告| 国语精品一区二区三区| 国产主播在线一区| 日本无码一区二区三区白峰美| 无码国产精品一区二区免费 | 成人中文字幕一区二区三区| 精品欧洲av无码一区二区| 精品人妻一区二区三区浪潮在线 | 久久久av波多野一区二区| 国产高清在线精品一区二区三区| 亚洲AV无码一区东京热久久| 中文字幕日韩一区二区三区不卡| 国产一区高清视频| 中文字幕一区二区三匹| 亚洲国产成人一区二区精品区| 视频一区视频二区制服丝袜| 中字幕一区二区三区乱码| 国产精品男男视频一区二区三区| 亚洲av无码一区二区三区四区 | 亚洲欧美国产国产综合一区| 国产亚洲一区二区三区在线| 日本一区二区不卡视频| 日本一区高清视频| 亚洲综合激情五月色一区| 亚洲欧洲无码一区二区三区| 日本高清一区二区三区 | 国产一区二区精品久久岳√| 无码国产精品一区二区高潮| 视频在线观看一区二区三区| 国产精品一区三区| 中文字幕在线无码一区| 久久精品一区二区三区四区| 精品国产aⅴ无码一区二区| 亚洲日韩国产一区二区三区在线| 久久青青草原一区二区| 无码人妻aⅴ一区二区三区有奶水| 国产精品久久久久一区二区三区 | 农村乱人伦一区二区| 无码av人妻一区二区三区四区| 亚洲乱码av中文一区二区| 国产在线不卡一区|