ES6實現圖片切換特效(圖片牆效果)

来源:https://www.cnblogs.com/chenyingying0/archive/2020/03/28/12588438.html
-Advertisement-
Play Games

按照國際慣例先放效果圖 貼代碼: index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> <link rel="stylesheet" href="index.css ...


按照國際慣例先放效果圖

貼代碼:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="wrap">
        <!-- <div class="img_container">
            <ul class="img_classify">
                <li class="img_classify_type_btn img_classify_type_btn_active">類別1</li>
                <li class="img_classify_type_btn">類別2</li>
            </ul>
            <div class="img_pic_container">
                <figure>
                    <img src="images/1.jpg" alt="1">
                    <figcaption>title</figcaption>
                </figure>
            </div>
        </div> -->
    </div>
    <!-- 遮罩層,預覽時出現大圖 -->
    <!-- <div class="img_overlay">
        <div class="img_overlay_prevbtn"></div>
        <div class="img_overlay_nextbtn"></div>
        <img src="images/1.jpg" alt="1">
    </div> -->

    <script src="index.js"></script>
    <script src="data.js"></script>
    <script>
        const img=new $Img({
            data,
            initType:"JavaScript",//預設顯示的分類
            outWrap:"#wrap"//所有DOM掛載點
        });
    </script>
</body>
</html>

index.css

*{
    margin:0;
    padding:0;
}
body{ 
    background: #fafafa;
    background: url('images/bg.png')
}
li{
    list-style:none;
}
a{
    text-decoration: none;
}
::-webkit-scrollbar {
    display: none;
}
#wrap{  
    width: 1065px;
    margin: 0 auto;
    padding: 30px;
    background: rgb(255, 255, 255);
    border-radius: 2px;
    margin-top: 100px;
}
.img_container{
    font-size: 10px;
}
.img_classify_type_btn{
    display: inline-block;
    padding: .2em 1em;
    font-size: 1.6em;
    margin-right: 10px;
    cursor: pointer;
    border: 1px solid #e95a44;
    outline: none;
    color: #e95a44;
    transition: all .4s;
    user-select: none;/*文字不允許用戶選中*/
    border-radius: 2px;
}
.img_classify_type_btn_active{
    background: #e95a44;
    color: #fff;
}
.img_pic_container{
    position: relative;
    margin-top: 30px;
    width: 1005px;
    display: flex;
    flex-wrap: wrap;
    transition: all .6s cubic-bezier(0.77, 0, 0.175, 1);/*動畫效果*/
}
.img_pic_container figure{
    width: 240px;
    height: 140px;
    position: absolute;
    transition: all .6s cubic-bezier(0.77, 0, 0.175, 1);
    transform: scale(0, 0);
    opacity: 0;
    overflow: hidden;
    border-radius: 2px;
    user-select: none;
}
/* 偽元素遮罩層 */
.img_pic_container figure::before {
    display: block;
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: 4;
    background: rgba(58, 12, 5, 0.5);
    content: ' ';
    font-size: 0;
    opacity: 0;
    transition: all .3s;
    cursor: pointer;
}
/* 圖片 */
.img_pic_container figure img {
    display: block;
    width: 100%;
    height: 100%;
    transition: all .3s;
}
/* 圖片標題 */
.img_pic_container figure figcaption {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 7;
    opacity: 0;
    font-size: 1.5em;
    color: rgb(255, 255, 255);
    transform: translate(-50%, -50%);
    transition: all .3s;
    text-align: center;
    cursor: pointer;
}
/* 懸停圖片的時候標題顯示 */
.img_pic_container figure:hover figcaption{
    opacity: 1;
}
.img_pic_container figure:hover img{
    transform: scale(1.1, 1.1);
}
/* 懸停圖片的時候遮罩顯示 */
.img_pic_container figure:hover::before{
    opacity: 1;
}
.img_overlay{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, .8);
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0;
    transition: all .3s;
    display: none;
    z-index: 99;
}
.img_overlay_prevbtn,
.img_overlay_nextbtn{
    position: absolute;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border: 2px solid white;
    text-align: center;
    line-height: 50px;
    color: white;
    font-size: 2rem;
    cursor: pointer;
}
.img_overlay_prevbtn{
    left: 20px;
}
.img_overlay_nextbtn{
    right: 20px;
}
.img_overlay_prevbtn:active,
.img_overlay_nextbtn:active{
    background: rgb(241, 241, 241, .4);
}
.img_overlay_nextbtn::after{
    content: "N";
}
.img_overlay_prevbtn::after{
    content: "P";
}
.img_overlay img {
  transform: scale(2, 2);
}

index.js

(function(window,document){

    let canChange=true;
    let curImgIndex=0;//預設顯示的圖片索引

    //公共方法(便於之後對DOM的操作)
    const methods={
        //同時添加多個子元素,對象簡潔表示法
        appendChilds(parent,...child){
            child.forEach(item=>{
                parent.appendChild(item);
            })
        },
        //選擇單個元素
        $(selector,root=document){
            return root.querySelector(selector);
        },
        //選擇多個元素
        $$(selector,root=document){
            return root.querySelectorAll(selector);
        }
    };

    // 構造函數
    let Img=function(options){
        this._init(options);//初始化,對圖片進行分類
        this._createElement();//生成DOM
        this._bind();//綁定事件
        this._show();//顯示到頁面上
    }

    //初始化
    Img.prototype._init=function({data,initType,outWrap}){
        this.types=["全部"];//全部分類
        this.all=[];//所有圖片
        this.classified={"全部":[]};//分類映射
        this.curType=initType;//當前顯示的圖片分類
        this.outWrap=methods.$(outWrap);//所有DOM掛載點
        this.imgContainer=null;//圖片部分容器(不包括分類按鈕)
        this.wrap=null;//圖片區域總容器(包括分類按鈕)
        this.typeBtnEls=null;//分類按鈕數組
        this.figures=null;//圖片數組

        this._classify(data);//對圖片進行分類
        //console.log(this.classified);//列印分類映射表

    }

    //對圖片進行分類
    Img.prototype._classify=function(data){
        let srcs=[];//存儲已經生成過的圖片,避免重覆生成

        data.forEach(({type,title,alt,src},index)=>{
            // arr.includes(a) 判斷數組中是否存在某個值
            // 如果分類的數組中,沒有當前分類,則添加當前分類
            if(!this.types.includes(type)){            
                this.types.push(type);
            }

            //Object.keys(obj) 返回obj中所有屬性名組成的數組
            //如果屬性名中不存在該分類,則添加該分類
            if(!Object.keys(this.classified).includes(type)){
                this.classified[type]=[];
            }

            //如果該圖片沒有生成過
            if(!srcs.includes(src)){
                srcs.push(src);

                //生成圖片
                let figure=document.createElement("figure");
                let img=document.createElement("img");
                let figcaption=document.createElement("figcaption");

                img.src=src;
                img.setAttribute("alt",alt);
                figcaption.innerText=title;

                methods.appendChilds(figure,img,figcaption);

                //添加到圖片數組中
                this.all.push(figure);

                //添加到分類映射中
                this.classified[type].push(this.all.length-1);

            }else{
                //如果該圖片已經生成過,就去srcs數組中找到對應圖片
                //srcs.findIndex(s1=>s1===src) 遍歷src數組,找到元素的值為src的,返回其下標
                this.classified[type].push(srcs.findIndex(s1=>s1===src));

            }
        })
    }

    //獲取對應分類下的圖片
    Img.prototype._getImgsByType=function(type){
        //如果分類是全部,就返回all數組
        //否則就去圖片映射表裡,找到該分類對應的圖片的索引;
        //通過map遍歷this.all數組,找到這些索引對應的圖片
        return type==="全部"?[...this.all]:this.classified[type].map(index=>this.all[index]);
    }

    //生成DOM
    Img.prototype._createElement=function(){
        let typesBtn=[];
        //根據分類數組,生成所有分類對應的按鈕元素
        for(let type of this.types.values()){    
            typesBtn.push(`
                <li class="img_classify_type_btn${ type===this.curType?' img_classify_type_btn_active':''}">${ type }</li>
            `);
        }

        //console.log(typesBtn);

        //整體模板
        let templates=`
            <ul class="img_classify">${ typesBtn.join("") }</ul>
            <div class="img_pic_container"></div>
        `;

        let wrap=document.createElement("div");
        wrap.className="img_container";
        wrap.innerHTML=templates;

        this.imgContainer=methods.$(".img_pic_container",wrap);

        //將分類下對應的圖片數組使用擴展運算符展開,添加到圖片容器中
        methods.appendChilds(this.imgContainer,...this._getImgsByType(this.curType));

        //取出可能會用到的元素,掛載到this上
        this.wrap=wrap;
        this.typeBtnEls=[...methods.$$(".img_classify_type_btn",wrap)];
        this.figures=[...methods.$$("figure",wrap)];//使用擴展運算符將取得的DOM元素轉數組

        //遮罩層
        let overlay=document.createElement("div");
        overlay.className="img_overlay";
        overlay.innerHTML=`
            <div class="img_overlay_prevbtn"></div>
            <div class="img_overlay_nextbtn"></div>
            <img src="" alt="">
        `;
        methods.appendChilds(this.outWrap,overlay);
        this.overlay=overlay;
        this.previewImg=methods.$("img",overlay);//當前要預覽的圖片

        this._calcPosition(this.figures);//修改每張圖片的定位
    }

    //映射關係
    Img.prototype._diff=function(curImgs,nextImgs){
        let diffArr=[];//保存映射關係
        // 如:當前[1,2,3,5,6],下一批[3,9,11,12,14]
        // 則映射為[[2,0],..] 
        // 兩組圖片中國相同的圖片為3,3在數組1的下標為2,3在數組2的下標為0,保存這種映射關係
        
        curImgs.forEach((src1,index1)=>{
            //遍歷當前src數組,對每一個src,去下一批的src數組中找是否有相同的,有則返回該src在下一批數組中的下標
            let index2=nextImgs.findIndex(src2=>src1===src2);

            //
            if(index2!=-1){
                diffArr.push([index1,index2]);
            }
        })

        return diffArr;

    }

    //綁定事件
    Img.prototype._bind=function(){
        //解構賦值,獲取到e.target
        methods.$(".img_classify",this.wrap).addEventListener("click",({target})=>{
            if(target.nodeName!=="LI") return;//如果點的不是li,則返回
            //console.log(target.innerText);
            
            if(!canChange) return;
            canChange=false;

            const type=target.innerText;
            const imgs=this._getImgsByType(type);//下一輪要顯示的所有圖片

            //目前出現的圖片的所有src
            let curImgs=this.figures.map(figure=>methods.$("img",figure).src);
            //點擊後下一批要出現的圖片的src
            let nextImgs=imgs.map(figure=>methods.$("img",figure).src);

            const diffArr=this._diff(curImgs,nextImgs);//得到兩組圖片共有的圖片映射關係
            //遍歷該映射
            diffArr.forEach(([,index2])=>{//index2是兩組中相同的圖片在下一組中的索引
                //every() 方法使用指定函數檢測數組中的所有元素:
                //如果數組中檢測到有一個元素不滿足,則整個表達式返回 false ,且剩餘的元素不會再進行檢測。
                //如果所有元素都滿足條件,則返回 true。
                this.figures.every((figure,index)=>{
                    let src=methods.$("img",figure).src;
                    if(src===nextImgs[index2]){
                        //splice() 方法向/從數組中添加/刪除項目
                        this.figures.splice(index,1);//找到相同的圖片,從上一輪的圖片數組中剔除
                        return false;
                    }
                    return true;
                })
            })

            this._calcPosition(imgs);

            let needAppendImgs=[];//切換下一輪時需要添加的元素(相同的元素不需要重覆添加)
            if(diffArr.length){
                //如果兩輪存在相同圖片,則相同的圖片 不需要重覆載入
                let nextIndex=diffArr.map(([,index2])=>index2);//相同的圖片的下標
                imgs.forEach((figure,index)=>{
                    if(!needAppendImgs.includes(index)){
                        needAppendImgs.push(figure);//如果該圖片不存在,則添加
                    }
                })
            }else{
                //如果不存在相同圖片,則所有圖片需要載入
                needAppendImgs=imgs;
            }

            //隱藏當前所有圖片
            this.figures.forEach(figure=>{
                figure.style.transform="scale(0,0) translate(0 100%)";
                figure.style.opacity="0";
            })

            //添加需要新增的圖片
            methods.appendChilds(this.imgContainer,...needAppendImgs);

            //顯示新一輪的圖片            
            setTimeout(()=>{
                imgs.forEach(el=>{                    
                    el.style.transform="scale(1,1) translate(0,0)";
                    el.style.opacity="1";    
                    //console.log(el);                
                })
            });

            //銷毀上一輪出現的所有圖片
            setTimeout(()=>{
                this.figures.forEach(figure=>{
                    this.imgContainer.removeChild(figure);            
                })

                this.figures=imgs;

                canChange=true;
            },600);//在css中動畫設置的結束時長就是0.6秒

            //切換按鈕樣式
            this.typeBtnEls.forEach(btn=>(btn.className="img_classify_type_btn"));
            target.className="img_classify_type_btn img_classify_type_btn_active";
        })

        //給每張圖片綁定點擊事件
        this.imgContainer.addEventListener("click",({target})=>{
            if(target.nodeName!=="FIGURE" && target.nodeName!=="FIGCAPTION") return;
            if(target.nodeName==="FIGCAPTION"){
                target=target.parentNode;
            }

            //顯示預覽的圖片和遮罩層
            const src=methods.$("img",target).src;
            curImgIndex=this.figures.findIndex(figure=>src===methods.$("img",figure).src);
            this.previewImg.src=src;
            this.overlay.style.display="flex";
            
            setTimeout(()=>{
                this.overlay.style.opacity="1";
            })
        })

        //點擊遮罩層,淡出
        this.overlay.addEventListener("click",()=>{
            this.overlay.style.opacity="0";
            setTimeout(()=>{
                this.overlay.style.display="none";
            },300);//300毫秒是css中transition設置的時間
        })

        //上一張下一張按鈕綁定
        methods.$(".img_overlay_prevbtn",this.overlay).addEventListener("click",e=>{
            //阻止事件冒泡,導致觸發點擊遮罩隱藏遮罩的情況
            e.stopPropagation();
            curImgIndex=curImgIndex===0?this.figures.length-1:curImgIndex-1;
            this.previewImg.src=methods.$("img",this.figures[curImgIndex]).src;
        })
        methods.$(".img_overlay_nextbtn",this.overlay).addEventListener("click",e=>{
            e.stopPropagation();
            curImgIndex=curImgIndex===this.figures.length-1?0:curImgIndex+1;
            this.previewImg.src=methods.$("img",this.figures[curImgIndex]).src;
        })
    }

    //顯示到頁面上
    Img.prototype._show=function(){
        methods.appendChilds(this.outWrap,this.wrap);//把圖片總容器掛載到指定的外容器上

        //演示器實現進場動畫
        setTimeout(()=>{
            //讓所有圖片顯示
            this.figures.forEach(figure=>{
                figure.style.transform="scale(1,1) translate(0,0)";
                figure.style.opacity="1";
            })
        },0)

    }

    //計算每張圖片的top和left
    Img.prototype._calcPosition=function(figures){
        figures.forEach((figure,index)=>{
            //140是每張圖片的高度,15是每張圖片垂直方向的間隙
            //240是每張圖片的寬度,15是每張圖片水平方向的間隙
            figure.style.top=parseInt(index/4)*140+parseInt(index/4)*15+"px";
            figure.style.left=parseInt(index%4)*(240+15)+"px";
            figure.style.transform="scale(0,0) translate(0,-100%)";//讓特效更豐富
        })

        //設置圖片容器高度
        var num=figures.length;//圖片數量
        if(num<=4){
            this.imgContainer.style.height="140px";
        }else{
            this.imgContainer.style.height=Math.ceil(num/4)*140+(Math.ceil(num/4)-1)*15+"px";
        }
        
    }

    window.$Img=Img;//暴露到全局

})(window,document);

data.js(數據)

const data = [

  {
    type: 'JavaScript',
    title: 'ES6快速入門',
    alt: 'ES6快速入門',
    src: './images/1.jpg'
  },

  {
    type: 'JavaScript',
    title: 'Javascript實現二叉樹演算法',
    alt: 'Javascript實現二叉樹演算法',
    src: './images/2.jpg'
  },

  {
    type: 'JavaScript',
    title: 'Canvas繪製時鐘',
    alt: 'Canvas繪製時鐘',
    src: './images/3.jpg'
  },

  {
    type: 'JavaScript',
    title: '基於websocket的火拼俄羅斯',
    alt: '基於websocket的火拼俄羅斯',
    src: './images/15.jpg'
  },

  {
    type: '前端框架',
    title: 'React知識點綜合運用實例',
    alt: 'React知識點綜合運用實例',
    src: './images/4.jpg'
  },

  {
    type: '前端框架',
    title: 'React組件',
    alt: 'React組件',
    src: './images/5.jpg'
  },

  {
    type: '前端框架',
    title: 'Vue+Webpack打造todo應用',
    alt: 'Vue+Webpack打造todo應用',
    src: './images/6.jpg'
  },

  {
    type: '前端框架',
    title: 'Vue.js入門基礎',
    alt: 'Vue.js入門基礎',
    src: './images/7.jpg'
  },

  {
    type: '前端框架',
    title: '使用Vue2.0實現購物車和地址選配功能',
    alt: '使用Vue2.0實現購物車和地址選配功能',
    src: './images/8.jpg'
  },

  {
    type: 'React',
    title: 'React知識點綜合運用實例',
    alt: 'React知識點綜合運用實例',
    src: './images/4.jpg'
  },

  {
    type: 'React',
    title: 'React組件',
    alt: 'React組件',
    src: './images/5.jpg'
  },

  {
    type: 'Vue.js',
    title: 'Vue+Webpack打造todo應用',
    alt: 'Vue+Webpack打造todo應用',
    src: './images/6.jpg'
  },

  {
    type: 'Vue.js',
    title: 'Vue.js入門基礎',
    alt: 'Vue.js入門基礎',
    src: './images/7.jpg'
  },

  {
    type: 'Vue.js',
    title: '使用Vue2.0實現購物車和地址選配功能',
    alt: '使用Vue2.0實現購物車和地址選配功能',
    src: './images/8.jpg'
  }

]

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • SQL編程 1).if-elseif-else語句 語法: if 條件 then //條件1 elseif 條件 then //條件2 else //條件3 end if; 示例演示: create procedure pro_9(in grade int) -- 輸入等級 begin if gra ...
  • 當前不少系統的資料庫依舊是MySQL5.6,由於MySQL5.7及MySQL8.0在性能及安全方面有著很大的提升,因此需要升級資料庫。本文通過邏輯方式、物理方式原地升級來介紹MySQL5.6 升級至MySQL5.7的方法,並介紹其使用場景。 1. 邏輯方式升級 邏輯方式升級其實就是通過邏輯備份工具( ...
  • 在SQL Server中,有時候查詢數據時,需要限定查詢時間範圍。此時需要對時間進行運算, 如下所示: USE AdventureWorks2014;GOSELECT *FROM HumanResources.EmployeeWHERE ModifiedDate > GETDATE() - 20; ... ...
  • 使用 WebView 配合 pdf.js 在 Android 上顯示 PDF 文件 ...
  • 一、Cookie SameSite屬性介紹 就像大家已經知道的,一旦設置Cookie之後,在Cookie失效之前瀏覽器會一直將這個Cookie在後續所有的請求中都傳回到Server端。我們的系統會利用Cookie這個特性做很多事情,但通常我們會在Cookie中存放加密的用戶身份,在Server端根據 ...
  • html5搜索框結合datalist可以實現帶搜索功能的下拉框 不過嘗試了下,使用optgroup分組發現沒效果 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>search</title> </head> ...
  • 我們的項目上有一個這樣的場景:一個下拉選擇框,同時要支持用戶輸入,將最終的結果顯示在文本框中(就是普通的字元串,用戶在下拉框中選擇的放在【】中)……不知道能不能想象出來,寫上一篇筆記的時候發現和咱們博客園選擇“tag 標簽”的功能有點接近啊,我們的ui還是跟她有些不同。 還是拿一個具體的例子說一下吧 ...
  • 2020-03-24 1.安裝Node.js 官網:https://nodejs.org/ 兩個版本 LTS為穩定的長期支持版本 Current為最新的版本 安裝完畢後,cmd下輸入 node -v 查看node版本 若顯示“不是內部命令。。。。” 請配置環境變數 這裡不贅述 2.安裝WePY 運行 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...