React視角下的輪播圖

来源:http://www.cnblogs.com/djtao/archive/2016/12/20/6204641.html
-Advertisement-
Play Games

天貓購物網站最顯眼的就是輪播圖了。我在學習一樣新js庫,一個新框架或新的編程思想的時候,總是感嘆“入門必做選項卡,進階須擼輪播圖。”作為一個React組件,它是狀態操控行為的典型,拿來練手是個不錯的選擇。 為了複習,這次就嘗試用原生的javascript+React來完成。 輪播圖原生實現 所謂輪播 ...


天貓購物網站最顯眼的就是輪播圖了。我在學習一樣新js庫,一個新框架或新的編程思想的時候,總是感嘆“入門必做選項卡,進階須擼輪播圖。”作為一個React組件,它是狀態操控行為的典型,拿來練手是個不錯的選擇。
為了複習,這次就嘗試用原生的javascript+React來完成。


輪播圖原生實現

所謂輪播圖其實是擴展版的選項卡。

先佈局

主幹架構

<div id="tabs">
        <ul id="btns">
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
        </ul>
        <ul id="imgs">
            <li><img src="images/banner1.jpg"></li>
            <li><img src="images/banner2.jpg"></li>
            <li><img src="images/banner3.jpg"></li>
            <li><img src="images/banner4.jpg"></li>
            <li><img src="images/banner5.jpg"></li>
            <li><img src="images/banner6.jpg"></li>
        </ul>
  </div>

樣式如下

/*css-reset*/
*{
  margin:0;
  padding: 0;
}
ul li{
  list-style: none;
}
img{
    border: none;
}
a{
  text-decoration: none;
}

/******************/
#tabs{
    width: 1130px;
    height: 500px;
    margin: 100px auto;
    position: relative;
    overflow: hidden;
}
#tabs li{
    float: left;
}
#tabs img{
    width: 1130px;
    height: 500px;
}
#btns{
    position: absolute;
    top:88%;
    left:395px;
    z-index: 9;
}
#btns a{
    display: block;
    width: 17px;
    height: 17px;
    background: rgba(0,0,0,0.3);
    border-radius: 50%;
    border: 2px solid rgba(0,0,0,0.3);
}
#btns li{
    margin: 10px;
}

大概效果

純javascript實現

事件

一個簡單的輪播圖包括多個事件。

  • 滑鼠移入移出:當滑鼠移出,或者是滑鼠不在輪播圖上面,執行自動播放
  • 當滑鼠移入:不再自動播放,而且點擊按鈕會執行跳轉到相應的頁面。

漸變

因為6張圖不是很多。所以考慮六張圖全部做絕對定位,按照順序疊加在一起。然再通過一個透明度的運動框架,實現之。
在此我選用這個運動框架:

function getStyle(obj,attr){
    if(obj.crrentStyle){
        return obj.currentStyle[attr];
        //相容IE8以下
    }else{
        return getComputedStyle(obj,false)[attr];
        //參數false已廢。照用就好
    }
}

function startMove(obj,json,fn){
    //清理定時器
    if(obj.timer){
        clearInterval(obj.timer);
    }
    obj.timer=setInterval(function(){
        var bStop=false;//如果為false就停了定時器!
        var iCur=0;
        // 處理屬性值
        for(var attr in json){
            if(attr=='opacity'){
                iCur=parseInt(parseFloat(getStyle(obj,attr))*100);
            }else{
                iCur=parseInt(getStyle(obj,attr));
            }
            //定義速度值
            var iSpeed=(json[attr]-iCur)/8;
            iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);
            //檢測停止:如果我發現某個值不等於目標點bStop就不能為true。
            if(iCur!==json[attr]){
                bStop=false;
            }
            if(attr=='opacity'){
                obj.style[attr]=(iCur+iSpeed)/100;
                obj.style.filter='alpha(opacity:'+(iCur+iSpeed)+')';
            }else{
                obj.style[attr]=iCur+iSpeed+'px';
            }
        }
        //檢測是否停止,是的話關掉定時器
        if(bStop===true){
            if(iCur==json[attr]){
                clearInterval(obj.timer);
                if(fn){
                    fn();
                }
            }
        }
    },30);
}

這個框架可以指定樣式值進行漸變。

不得不說,這確實是一個很棒的運動框架。可以把它單獨放在為一個名為move.js的文件中再引入。

根據這個思路寫出原生的代碼:

window.onload=function(){
    var oTab=document.getElementById('tabs');
    var oBtns=document.getElementById('btns');
    var aBtns=document.getElementsByTagName('a');
    var oImgs=document.getElementById('imgs');
    var aImgsLi=oImgs.getElementsByTagName('li');
    var bCheck=true;
    var iNow=0;

    // 以下是初始化設置:
    aBtns[0].style.background='rgba(255,255,255,0.5)';
    aImgsLi[0].style.zIndex=6;


    function iNowlistener(){//改變的核心函數
        // 初始化
        for(var i=0;i<aBtns.length;i++){
            aBtns[i].style.background='rgba(0,0,0,0.3)';
        }
        aBtns[iNow].style.background='rgba(255,255,255,0.5)';
        for(var j=0;j<aBtns.length;j++){
            aImgsLi[j].style.opacity=0;
            if(j!==iNow){
                aImgsLi[j].style.display='none';
            }else{
                aImgsLi[j].style.display='block';
                startMove(aImgsLi[j],{'opacity':100});
            }
        }
    }


    var timer=null;
    timer=setInterval(function(){
        if(bCheck){
            if(iNow==5){//將最後一個變為0
                iNow=0;
            }else{
                iNow++;
            }
            iNowlistener();
        }else{
            return false;
        }
    },2000);


    oTab.onmouseover=function(){
        bCheck=false;
        for(var i=0;i<aBtns.length;i++){
            aBtns[i].index=i;
            aBtns[i].onmouseover=function(){
                if(this.index==iNow){
                    return false;
                }else{
                    iNow=this.index;
                    iNowlistener();
                }
            };
        }

    };

    oTab.onmouseout=function(){
        bCheck=true;
    };

};

效果如下:

不得不說,原生的代碼寫起來好長好長。

很長嗎?後面的更長。


React思路

以上原生代碼已經經過了初步的封裝——比如INowListener。但是在React的價值觀來說,顯然還需要進一步的封裝。甚至重新拆分。最理想的情況是:頂層組件作為主幹架構和狀態機。下層組件接收狀態並運行方法。

多少個組件?

在這個輪播圖中,就三個組件。

- Tabs
   -imgs
   -btns
var Tabs=React.createClass({
            render:function(){

                return (
                    <div id="tabs">
                        <Btns/>
                        <Imgs/>
                    </div>
                );
            }
        });

        var Btns=React.createClass({
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=
                      <li key={i.toString()}><a href="javascript:;"></a></li>
                    arr.push(btnContent);
                }
                return (
                    <ul id="btns">{arr}</ul>
                )
            }
        });

        var Imgs=React.createClass({
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var imgContent=
                      <li key={i.toString()}><img src={"images/banner"+(i+1)+".jpg"}/></li>
                    arr.push(imgContent);
                    console.log(arr)
                }
                return (
                    <ul id="imgs">{arr}</ul>
                );
            }
        });

        ReactDOM.render(
            <Tabs/>,
            document.getElementById('example')
        )

這樣寫就把樣式寫出來了。

哪個是狀態?

iNOW是狀態。而且是最重要的狀態!既然這樣,就考慮把狀態iNow放頂層。

滑鼠懸停看起來也是狀態,但懸停按鈕上,觸發iNow改變——因此還是iNow。

滑鼠移入移出事件,應該是狀態。但是這個移入移出的狀態依賴於iNow。所以不能單獨用。

需要哪些props?

構造組件時,為了靈活性,一般都不考慮把組件框架寫死。比如圖片張數,id名,等等都應該是props。但是這些暫時來說,都是次要的。

狀態肯定是一個核心props,此外,底層設置狀態的回調也是核心的props之一。

空談太多無意義,接下來嘗試實現!


自動按鈕

現在先不考慮其它,單看按鈕。
在插入文檔之後,開啟一個定時器,每隔2000ms執行一次狀態更新。

setState的寫法

那涉及到了iNow狀態根據前一個狀態更新,官方文檔不建議這種寫法:

this.setState({
    return {
        iNow:this.state.iNow+1
    }
})

因為狀態更新可能是非同步的。這樣寫很容易出問題。
事實上,官網提供了這樣的寫法:

this.setState(function(prev,props){
    return {
        iNow:prev.iNow+1
    }
})

在這裡只用第一個參數就夠了。

想當然的按鈕

定時器應該是一個狀態計算器。

所以按鈕可以這麼寫:

var Btns=React.createClass({
            getInitialState:function(){
                return ({
                    iNow:0
                })
            },
            componentDidMount:function(){
                var _this=this;
                setInterval(function(){
                    _this.setState(function(prev){
                        //console.log(prev)
                        if(prev.iNow==5){
                            return {
                                iNow:0
                            };
                        }else{
                            return {
                                iNow:prev.iNow+1
                            };
                        }
                    })
                },2000);
            },
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=null;
                    if(i==this.state.iNow){
                        btnContent=
                          <li key={i.toString()}><a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a></li>
                    }else{
                        btnContent=
                          <li key={i.toString()}><a href="javascript:;"></a></li>
                    }

                    arr.push(btnContent);
                }
                
                return (
                    <ul id="btns">{arr}</ul>
                );
            }
        });

按鈕就實現了。
看起來不錯,但是這樣寫可能在未來造成極大的不便。

懸停交互

再強調一次價值觀這個概念,按照React的價值觀,狀態應該從頂層傳下去,況且在這個案例中,頂層Tabs組件做一件事就夠了:狀態機,在Btn組件插入到文檔之後,打開這個定時器。底層組件比如Btns根據狀態每隔2000ms通過props刷新變化。

同時,我還要實現一個簡單的交互功能:當滑鼠懸停在Tabs上時,不再允許iNow自動更新。——可以做一個bCheck開關,當Tabs組件滑鼠移入/移出時,觸發bCheck的來回變化。

此處可能有個小問題,就是滑鼠一道按鈕組上時,會造成bCheck抖動。但是最後又變回false。所以認為不影響。

很自然想到,bCheck為false時,關閉定時器。但是這樣做又等於浪費了定時器的功能,回調方法中一旦關掉定時器,再重新定時器就不是一般的麻煩了,為什麼不直接在定時器做判斷呢?所以我認為不應該讓定時器停下來。只需要改變定時器計算iNow的行為就行了。

var Tabs=React.createClass({
            getInitialState:function(){
                return {
                    iNow:0,
                    bCheck:true//為false時不允許定時器計算更新iNow
                }
            },
            setInow:function(){
            var _this=this;
            var timer=setInterval(function(){
                  if(_this.state.bCheck){
                      //console.log(_this.state.bCheck)
                      _this.setState(function(prev){
                          if(prev.iNow==5){
                              return {
                                  iNow:0
                              };
                          }else{
                              return {
                                  iNow:prev.iNow+1
                              };
                          }
                      });
                  }else{
                      console.log('該停了!')
                      return false;
                  }

              },2000);

          },
            checkSwitch:function(){
                this.setState(function(prev){
                    return {
                        bCheck:!prev.bCheck,
                    }
                })
            },
            render:function(){
                return (
                    <div id="tabs" onMouseOver={this.checkSwitch} onMouseOut={this.checkSwitch}>
                        <Btns iNow={this.state.iNow} setInow={this.setInow}/>
                        <Imgs/>
                    </div>
                );
            }
        });

        var Btns=React.createClass({
            componentDidMount:function(){
                this.props.setInow();//插入後就執行回調方法
            },
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=null;
                    if(i==this.props.iNow){
                        btnContent=
                          <li key={i.toString()}>
                          <a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a>
                          </li>
                    }else{
                        btnContent=
                          <li key={i.toString()}><a href="javascript:;"></a></li>
                    }

                    arr.push(btnContent);
                }

                return (
                    <ul id="btns">{arr}</ul>
                );
            }
        });

圖片動畫

一件事三個步驟

圖片組件雖說只是做一件事情(根據iNow渲染效果),但是也得分三步來做。

  • 首先,渲染前應該保證索引值非iNow的所有圖片display為none。索引值為iNow的圖片透明度為0。(初始化)

  • 其次,在首次插入文檔完畢之後(componentDidMount),對第0張圖執行startMove函數。

  • 第三,需要一個監聽頂層iNow的方法。定時器已經給Btns組件用了,再用就會出錯。

留意到Imgs組件實際上只接受一個會變化的props那就是iNow。因此採用componentWillReceiveProps

生命周期方法

componentWillReceiveProps

組件接收到新的props時調用,並將其作為參數nextProps使用,此時可以更改組件propsstate

    componentWillReceiveProps: function(nextProps) {
        if (nextProps.bool) {
            this.setState({
                bool: true
            });
        }
    }

這裡採用的兩個組件周期方法都是組件真實存在時的方法。所以可以直接使用真實的DOM命令。

實現

var Tabs=React.createClass({
        getInitialState:function(){
            return {
                iNow:0,
                bCheck:true
            };
        },
        setInow:function(){
            var _this=this;
            var timer=setInterval(function(){
                if(_this.state.bCheck){
                    //console.log(_this.state.bCheck)
                    _this.setState(function(prev){
                        if(prev.iNow==5){
                            return {
                                iNow:0
                            };
                        }else{
                            return {
                                iNow:prev.iNow+1
                            };
                        }
                    });
                }else{
                    console.log('該停了!')
                    return false;
                }

            },2000);

        },
        checkSwitch:function(){
            console.log(this.state.bCheck)
            this.setState(function(prev){
                return {
                    bCheck:!prev.bCheck
                };
            });
        },
        render:function(){
            return (
                <div id="tabs"
                  onMouseOver={this.checkSwitch}
                  onMouseOut={this.checkSwitch}>
                    <Btns iNow={this.state.iNow}
                      setInow={this.setInow} />
                    <Imgs iNow={this.state.iNow}/>
                </div>
            );
        }
    });

    var Btns=React.createClass({
        componentDidMount:function(){
            this.props.setInow();
        },

        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var btnsContent=null;
                if(i==this.props.iNow){
                    btnsContent=
                        <li key={i.toString()}>
                            <a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a>
                        </li>
                }else{
                    btnsContent=
                        <li key={i.toString()}>
                            <a href="javascript:;"></a>
                        </li>
                }
                arr.push(btnsContent);
            }

            return (
                <ul id="btns">{arr}</ul>
            );
        }
    });

    var Imgs=React.createClass({
        componentDidMount:function(){//剛開始載入時,就執行動畫函數
            var iNow=this.props.iNow;
            var obj=document.getElementById('imgs').getElementsByTagName('li')[iNow].childNodes[0];
            startMove(obj,{'opacity':100});
        },
        componentWillReceiveProps:function(nextProps){
            var obj=document.getElementById('imgs').getElementsByTagName('li')[nextProps.iNow].childNodes[0];
            //console.log(obj)
            startMove(obj,{'opacity':100});
        },
        // this.startMove:startMove(),
        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var imgsContent=null
                if(i==this.props.iNow){
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{opacity:'0'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }else{
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{display:'none'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }

            }

            return (
                <ul id="imgs">{arr}</ul>
            )
        }
    })

    ReactDOM.render(
        <Tabs/>,
        document.getElementById('example')
    );

看起來Imgs組件已經很完備了。——就它的功能來說已經沒有什麼需要添加了。


滑鼠懸停改變iNow

這個事件只能在底層組件Btns上實現。所以要拿到懸停的索引值。

然後通過回調,把該按鈕的索引值設置為整個組件Tabs的狀態iNow。

為了乾這兩件事,還是用一個changeInow(e)函數來包裝它們。

給誰綁定?加什麼事件?

為了忠實原來的代碼。我給a標簽加onMouseOver事件。

加了事件直接,秉承這React的核心價值觀(一個組件只乾一件事),我把get到的index值通過this.props.setInow傳遞迴去。只要頂層的iNow變了,下麵的組件不管什麼狀態,都會乖乖聽話了。

如何獲取當前懸停的索引值?

在Jquery很容易使用index方法來獲取索引值。但是在原生方法中,還得費一番周章。

給所有a綁定一個onMouseOver事件,假設該事件方法的參數為e,那麼e.target就是該參數的方法。

這需要寫一個getIndex方法

...
getIndex:function(e){
  var list=e.target.parentNode.parentNode.childNodes;
  for(var i=0;i<list.length;i++){
    if(list[i]===e.target.parentNode){
      return  i;
    }
  }
},
...

拿到索引值之後

——就把它設置為頂層的iNow。

既然決定通過this.props.setInow回調,那麼還得傳一個索引值參數,回到頂層稍微修改下方法,就實現了。

全部代碼:

var Tabs=React.createClass({//頂層組件
        getInitialState:function(){
            return {
                iNow:0,
                bCheck:true
            };
        },
        setInow:function(index){//核心狀態計算工具:依賴定時器進行實時刷新
            if(index!==undefined){//如果參數有內容。
                this.setState({
                    iNow:index
                });
            }else{
                var _this=this;
                this.timer=setInterval(function(){
                    if(_this.state.bCheck){
                        //console.log(_this.state.bCheck)
                        _this.setState(function(prev){
                            if(prev.iNow==5){
                                return {
                                    iNow:0
                                };
                            }else{
                                return {
                                    iNow:prev.iNow+1
                                };
                            }
                        });
                    }else{
                        //console.log('該停了!')
                        return false;
                    }
                },2000);
            }
        },
        checkSwitch:function(){
            //console.log(this.state.bCheck)
            this.setState(function(prev){
                return {
                    bCheck:!prev.bCheck
                };
            });
        },
        render:function(){
            return (
                <div id="tabs"
                  onMouseOver={this.checkSwitch}
                  onMouseOut={this.checkSwitch}>
                    <Btns iNow={this.state.iNow}
                      setInow={this.setInow} />
                    <Imgs iNow={this.state.iNow}/>
                </div>
            );
        }
    });

    var Btns=React.createClass({
        componentDidMount:function(){
            this.props.setInow();
        },
        getIndex:function(e){//獲取a的父級索引值
            var list=e.target.parentNode.parentNode.childNodes;
            for(var i=0;i<list.length;i++){
                if(list

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

-Advertisement-
Play Games
更多相關文章
  • TYPESDK 服務端設計思路與架構之一:應用場景分析 作為一個渠道SDK統一接入框架,TYPESDK從一開始,所面對的需求場景就是多款游戲,通過一個統一的SDK服務端,能夠同時接入幾十個甚至幾百個各種渠道的SDK。而且這些渠道介面的具體接入欄位和接入邏輯,每個月以至每周,都可能發生或大或小的變動。 ...
  • 好久沒寫代碼了,終於好不容易接到了開發任務,一看時間還挺充足的,我就慢慢整吧,若是遇上趕進度,基本上直接是功能優先,完全不考慮設計。你可以認為我完全沒有追求,當身後有鞭子使勁趕的時候,神馬設計都是浮雲,按時上線才是王道,畢竟領導是不會關註過程和代碼質量的,領導只看結果,這也許就是我等天朝碼農的悲哀。 ...
  • datepicker可以為bootstrap添加一個事件選擇控制項,適用於任何需要調用的場合,支持多種事件格式輸出(比如:dd, d, mm, m, yyyy, yy等),是製作網頁不可缺失的插件。 Requirements Bootstrap 2.0.4+ jQuery 1.7.1+ 線上文檔 Da ...
  • 一、閉包(Closure) 1.1、閉包相關的問題 請在頁面中放10個div,每個div中放入字母a-j,當點擊每一個div時顯示索引號,如第1個div顯示0,第10個顯示9;方法:找到所有的div,for迴圈綁定事件。 示例代碼: 運行結果: 因為點擊事件的函數內部使用外部的變數i一直在變化,當我 ...
  • 在平常項目開發過程中,經常會遇到需要在JavaScript中處理時間的情況,無非兩種(1,邏輯處理 2,格式轉換處理)。當然要說相關技術博,園子里閉著眼睛都能抓一把,但是我要做的是:既然有幸被我碰到了,就要儘可能的分析轉化為自己最適合自己的東西,成為自己知識庫的一部分;同時希望能幫助有需要的同學解決 ...
  • ▓▓▓▓▓▓ 大致介紹 jQuery Validate 插件為表單提供了強大的驗證功能,讓客戶端表單驗證變得更簡單,同時提供了大量的定製選項,滿足應用程式各種需求。該插件捆綁了一套有用的驗證方法,包括 URL 和電子郵件驗證,同時提供了一個用來編寫用戶自定義方法的 API。所有的捆綁方法預設使用英語 ...
  • 1、html結構 2、js 3、圖片案例 ...
  • 1、HTML結構 2、js 3、圖片案例 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...