08JavaScript-移動(dòng)端

觸屏事件概述

移動(dòng)端瀏覽器兼容性較好,我們不需要考慮以前 JS 的兼容性問(wèn)題,可以放心的使用原生 JS 書(shū)寫(xiě)效果,但是移動(dòng)端也有自己獨(dú)特的地方。比如觸屏事件 touch(也稱觸摸事件),Android和 IOS 都有。

touch 對(duì)象代表一個(gè)觸摸點(diǎn)。觸摸點(diǎn)可能是一根手指,也可能是一根觸摸筆。觸屏事件可響應(yīng)用戶手指(或觸控筆)對(duì)屏幕或者觸控板操作。

常見(jiàn)的觸屏事件如下:


image.png

觸摸事件對(duì)象(TouchEvent)

TouchEvent 是一類(lèi)描述手指在觸摸平面(觸摸屏、觸摸板等)的狀態(tài)變化的事件。這類(lèi)事件用于描述一個(gè)或多個(gè)觸點(diǎn),使開(kāi)發(fā)者可以檢測(cè)觸點(diǎn)的移動(dòng),觸點(diǎn)的增加和減少,等等


image.png

因?yàn)槠綍r(shí)我們都是給元素注冊(cè)觸摸事件,所以重點(diǎn)記住 targetTocuhes

touchstart、touchmove、touchend 三個(gè)事件都會(huì)各自有事件對(duì)象。

      <script>
        // 觸摸事件對(duì)象
        // 1. 獲取元素
        // 2. 手指觸摸DOM元素事件
        var div = document.querySelector('div');
        div.addEventListener('touchstart', function(e) {
            // console.log(e);
            // touches 正在觸摸屏幕的所有手指的列表 
            // targetTouches 正在觸摸當(dāng)前DOM元素的手指列表
            // 如果偵聽(tīng)的是一個(gè)DOM元素,他們兩個(gè)是一樣的
            // changedTouches 手指狀態(tài)發(fā)生了改變的列表 從無(wú)到有 或者 從有到無(wú)
            // 因?yàn)槲覀円话愣际怯|摸元素 所以最經(jīng)常使用的是 targetTouches
            console.log(e.targetTouches[0]);
            // targetTouches[0] 就可以得到正在觸摸dom元素的第一個(gè)手指的相關(guān)信息比如 手指的坐標(biāo)等等


        });
        // 3. 手指在DOM元素身上移動(dòng)事件
        div.addEventListener('touchmove', function() {


        });
        // 4. 手指離開(kāi)DOM元素事件
        div.addEventListener('touchend', function(e) {
            // console.log(e);
            // 當(dāng)我們手指離開(kāi)屏幕的時(shí)候,就沒(méi)有了 touches 和 targetTouches 列表
            // 但是會(huì)有 changedTouches


        });
    </script>
案例:移動(dòng)端拖動(dòng)元素
  1. touchstart、touchmove、touchend可以實(shí)現(xiàn)拖動(dòng)元素

  2. 但是拖動(dòng)元素需要當(dāng)前手指的坐標(biāo)值 我們可以使用 targetTouches[0] 里面的pageX 和 pageY

  3. 移動(dòng)端拖動(dòng)的原理: 手指移動(dòng)中,計(jì)算出手指移動(dòng)的距離。然后用盒子原來(lái)的位置 + 手指移動(dòng)的距離

  4. 手指移動(dòng)的距離: 手指滑動(dòng)中的位置 減去 手指剛開(kāi)始觸摸的位置

    拖動(dòng)元素三步曲:

    (1) 觸摸元素 touchstart: 獲取手指初始坐標(biāo),同時(shí)獲得盒子原來(lái)的位置

    (2) 移動(dòng)手指 touchmove: 計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子

    (3) 離開(kāi)手指 touchend:

    注意: 手指移動(dòng)也會(huì)觸發(fā)滾動(dòng)屏幕所以這里要阻止默認(rèn)的屏幕滾動(dòng) e.preventDefault();

  // (1) 觸摸元素 touchstart:  獲取手指初始坐標(biāo),同時(shí)獲得盒子原來(lái)的位置
        // (2) 移動(dòng)手指 touchmove:  計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子
        // (3) 離開(kāi)手指 touchend:
        var div = document.querySelector('div');
        var startX = 0; //獲取手指初始坐標(biāo)
        var startY = 0;
        var x = 0; //獲得盒子原來(lái)的位置
        var y = 0;
        div.addEventListener('touchstart', function(e) {
            //  獲取手指初始坐標(biāo)
            startX = e.targetTouches[0].pageX;
            startY = e.targetTouches[0].pageY;
            x = this.offsetLeft;
            y = this.offsetTop;
        });

        div.addEventListener('touchmove', function(e) {
            //  計(jì)算手指的移動(dòng)距離: 手指移動(dòng)之后的坐標(biāo)減去手指初始的坐標(biāo)
            var moveX = e.targetTouches[0].pageX - startX;
            var moveY = e.targetTouches[0].pageY - startY;
            // 移動(dòng)我們的盒子 盒子原來(lái)的位置 + 手指移動(dòng)的距離
            this.style.left = x + moveX + 'px';
            this.style.top = y + moveY + 'px';
            e.preventDefault(); // 阻止屏幕滾動(dòng)的默認(rèn)行為
        });
移動(dòng)端常見(jiàn)特效

移動(dòng)端輪播圖功能和基本PC端一致。

  1. 可以自動(dòng)播放圖片
  2. 手指可以拖動(dòng)播放輪播圖

案例分析:

  1. 自動(dòng)播放功能
  2. 開(kāi)啟定時(shí)器
  3. 移動(dòng)端移動(dòng),可以使用translate 移動(dòng)
  4. 想要圖片優(yōu)雅的移動(dòng),請(qǐng)?zhí)砑舆^(guò)渡效果


    image.png
  5. 自動(dòng)播放功能-無(wú)縫滾動(dòng)
  6. 注意,我們判斷條件是要等到圖片滾動(dòng)完畢再去判斷,就是過(guò)渡完成后判斷
  7. 此時(shí)需要添加檢測(cè)過(guò)渡完成事件 transitionend
  8. 判斷條件:如果索引號(hào)等于 3 說(shuō)明走到最后一張圖片,此時(shí) 索引號(hào)要復(fù)原為 0
  9. 此時(shí)圖片,去掉過(guò)渡效果,然后移動(dòng)
  10. 如果索引號(hào)小于0, 說(shuō)明是倒著走, 索引號(hào)等于2
  11. 此時(shí)圖片,去掉過(guò)渡效果,然后移動(dòng)


    image.png
  • 完整版:
window.addEventListener('load', function() {
    // alert(1);
    // 1. 獲取元素 
    var focus = document.querySelector('.focus');
    var ul = focus.children[0];
    // 獲得focus 的寬度
    var w = focus.offsetWidth;
    var ol = focus.children[1];
    // 2. 利用定時(shí)器自動(dòng)輪播圖圖片
    var index = 0;
    var timer = setInterval(function() {
        index++;
        var translatex = -index * w;
        ul.style.transition = 'all .3s';
        ul.style.transform = 'translateX(' + translatex + 'px)';
    }, 2000);
    // 等著我們過(guò)渡完成之后,再去判斷 監(jiān)聽(tīng)過(guò)渡完成的事件 transitionend 
    ul.addEventListener('transitionend', function() {
        // 無(wú)縫滾動(dòng)
        if (index >= 3) {
            index = 0;
            // console.log(index);
            // 去掉過(guò)渡效果 這樣讓我們的ul 快速的跳到目標(biāo)位置
            ul.style.transition = 'none';
            // 利用最新的索引號(hào)乘以寬度 去滾動(dòng)圖片
            var translatex = -index * w;
            ul.style.transform = 'translateX(' + translatex + 'px)';
        } else if (index < 0) {
            index = 2;
            ul.style.transition = 'none';
            // 利用最新的索引號(hào)乘以寬度 去滾動(dòng)圖片
            var translatex = -index * w;
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }
        // 3. 小圓點(diǎn)跟隨變化
        // 把ol里面li帶有current類(lèi)名的選出來(lái)去掉類(lèi)名 remove
        ol.querySelector('.current').classList.remove('current');
        // 讓當(dāng)前索引號(hào) 的小li 加上 current   add
        ol.children[index].classList.add('current');
    });

    // 4. 手指滑動(dòng)輪播圖 
    // 觸摸元素 touchstart: 獲取手指初始坐標(biāo)
    var startX = 0;
    var moveX = 0; // 后面我們會(huì)使用這個(gè)移動(dòng)距離所以要定義一個(gè)全局變量
    var flag = false;
    ul.addEventListener('touchstart', function(e) {
        startX = e.targetTouches[0].pageX;
        // 手指觸摸的時(shí)候就停止定時(shí)器
        clearInterval(timer);
    });
    // 移動(dòng)手指 touchmove: 計(jì)算手指的滑動(dòng)距離, 并且移動(dòng)盒子
    ul.addEventListener('touchmove', function(e) {
        // 計(jì)算移動(dòng)距離
        moveX = e.targetTouches[0].pageX - startX;
        // 移動(dòng)盒子:  盒子原來(lái)的位置 + 手指移動(dòng)的距離 
        var translatex = -index * w + moveX;
        // 手指拖動(dòng)的時(shí)候,不需要?jiǎng)赢?huà)效果所以要取消過(guò)渡效果
        ul.style.transition = 'none';
        ul.style.transform = 'translateX(' + translatex + 'px)';
        flag = true; // 如果用戶手指移動(dòng)過(guò)我們?cè)偃ヅ袛喾駝t不做判斷效果
        e.preventDefault(); // 阻止?jié)L動(dòng)屏幕的行為
    });
    // 手指離開(kāi) 根據(jù)移動(dòng)距離去判斷是回彈還是播放上一張下一張
    ul.addEventListener('touchend', function(e) {
        if (flag) {
            // (1) 如果移動(dòng)距離大于50像素我們就播放上一張或者下一張
            if (Math.abs(moveX) > 50) {
                // 如果是右滑就是 播放上一張 moveX 是正值
                if (moveX > 0) {
                    index--;
                } else {
                    // 如果是左滑就是 播放下一張 moveX 是負(fù)值
                    index++;
                }
                var translatex = -index * w;
                ul.style.transition = 'all .3s';
                ul.style.transform = 'translateX(' + translatex + 'px)';
            } else {
                // (2) 如果移動(dòng)距離小于50像素我們就回彈
                var translatex = -index * w;
                ul.style.transition = 'all .1s';
                ul.style.transform = 'translateX(' + translatex + 'px)';
            }
        }
        // 手指離開(kāi)的時(shí)候就重新開(kāi)啟定時(shí)器
        clearInterval(timer);
        timer = setInterval(function() {
            index++;
            var translatex = -index * w;
            ul.style.transition = 'all .3s';
            ul.style.transform = 'translateX(' + translatex + 'px)';
        }, 2000);
    });


    // 返回頂部模塊制作
    var goBack = document.querySelector('.goBack');
    var nav = document.querySelector('nav');
    window.addEventListener('scroll', function() {
        if (window.pageYOffset >= nav.offsetTop) {
            goBack.style.display = 'block';
        } else {
            goBack.style.display = 'none';
        }
    });
    goBack.addEventListener('click', function() {
        window.scroll(0, 0);
    })
})

classList 屬性

classList屬性是HTML5新增的一個(gè)屬性,返回元素的類(lèi)名。但是ie10以上版本支持。
該屬性用于在元素中添加,移除及切換 CSS 類(lèi)。有以下方法
element.classList.add(’類(lèi)名’);

focus.classList.add('current');

移除類(lèi):

element.classList.remove(’類(lèi)名’);

focus.classList.remove('current');

切換類(lèi):

element.classList.toggle(’類(lèi)名’);

focus.classList.toggle('current');

注意:以上方法里面,所有類(lèi)名都不帶點(diǎn)


click 延時(shí)解決方案

移動(dòng)端 click 事件會(huì)有 300ms 的延時(shí),原因是移動(dòng)端屏幕雙擊會(huì)縮放(double tap to zoom) 頁(yè)面。
解決方案:

  1. 禁用縮放。 瀏覽器禁用默認(rèn)的雙擊縮放行為并且去掉300ms 的點(diǎn)擊延遲。
 <meta name="viewport" content="user-scalable=no">
  • 2.利用touch事件自己封裝這個(gè)事件解決300ms 延遲。
    原理就是:
  1. 當(dāng)我們手指觸摸屏幕,記錄當(dāng)前觸摸時(shí)間
  2. 當(dāng)我們手指離開(kāi)屏幕, 用離開(kāi)的時(shí)間減去觸摸的時(shí)間
  3. 如果時(shí)間小于150ms,并且沒(méi)有滑動(dòng)過(guò)屏幕, 那么我們就定義為點(diǎn)擊
//封裝tap,解決click 300ms 延時(shí)
function tap (obj, callback) {
        var isMove = false;
        var startTime = 0; // 記錄觸摸時(shí)候的時(shí)間變量
        obj.addEventListener('touchstart', function (e) {
            startTime = Date.now(); // 記錄觸摸時(shí)間
        });
        obj.addEventListener('touchmove', function (e) {
            isMove = true;  // 看看是否有滑動(dòng),有滑動(dòng)算拖拽,不算點(diǎn)擊
        });
        obj.addEventListener('touchend', function (e) {
            if (!isMove && (Date.now() - startTime) < 150) {  // 如果手指觸摸和離開(kāi)時(shí)間小于150ms 算點(diǎn)擊
                callback && callback(); // 執(zhí)行回調(diào)函數(shù)
            }
            isMove = false;  //  取反 重置
            startTime = 0;
        });
}
//調(diào)用  
  tap(div, function(){   // 執(zhí)行代碼  });
  • 3.使用插件。fastclick 插件解決300ms 延遲。
 <script>
        if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
        }
        var div = document.querySelector('div');
        div.addEventListener('click', function() {
            alert(11);
        })
    </script>

移動(dòng)端常用開(kāi)發(fā)插件

什么是插件

移動(dòng)端要求的是快速開(kāi)發(fā),所以我們經(jīng)常會(huì)借助于一些插件來(lái)幫我完成操作,那么什么是插件呢?

JS 插件是 js 文件,它遵循一定規(guī)范編寫(xiě),方便程序展示效果,擁有特定功能且方便調(diào)用。如輪播圖和瀑布流插件。

特點(diǎn):它一般是為了解決某個(gè)問(wèn)題而專門(mén)存在,其功能單一,并且比較小。

我們以前寫(xiě)的animate.js 也算一個(gè)最簡(jiǎn)單的插件

fastclick 插件解決 300ms 延遲。 使用延時(shí)

GitHub官網(wǎng)地址: https://github.com/ftlabs/fastclick

插件的使用

  1. 引入 js 插件文件。

  2. 按照規(guī)定語(yǔ)法使用。

  3. fastclick 插件解決 300ms 延遲。 使用延時(shí)

  4. GitHub官網(wǎng)地址: https://github.com/ftlabs/fastclick

if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function() {
                       FastClick.attach(document.body);
            }, false);
}

Swiper 插件的使用

中文官網(wǎng)地址: https://www.swiper.com.cn/

  1. 引入插件相關(guān)文件。

  2. 按照規(guī)定語(yǔ)法使用

其他移動(dòng)端常見(jiàn)插件

lsuperslide: http://www.superslide2.com/
l iscroll: https://github.com/cubiq/iscroll

插件的使用總結(jié)

1.確認(rèn)插件實(shí)現(xiàn)的功能

2.去官網(wǎng)查看使用說(shuō)明

3.下載插件

4.打開(kāi)demo實(shí)例文件,查看需要引入的相關(guān)文件,并且引入

5.復(fù)制demo實(shí)例文件中的結(jié)構(gòu)html,樣式css以及js代碼

移動(dòng)端視頻插件 zy.media.js

H5 給我們提供了 video 標(biāo)簽,但是瀏覽器的支持情況不同。

不同的視頻格式文件,我們可以通過(guò)source解決。

但是外觀樣式,還有暫停,播放,全屏等功能我們只能自己寫(xiě)代碼解決。

這個(gè)時(shí)候我們可以使用插件方式來(lái)制作。

我們可以通過(guò) JS 修改元素的大小、顏色、位置等樣式。

移動(dòng)端常用開(kāi)發(fā)框架

移動(dòng)端視頻插件 zy.media.js

框架,顧名思義就是一套架構(gòu),它會(huì)基于自身的特點(diǎn)向用戶提供一套較為完整的解決方案。框架的控制權(quán)在框架本身,使用者要按照框架所規(guī)定的某種規(guī)范進(jìn)行開(kāi)發(fā)。

插件一般是為了解決某個(gè)問(wèn)題而專門(mén)存在,其功能單一,并且比較小。

前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能開(kāi)發(fā)PC端,也能開(kāi)發(fā)移動(dòng)端

前端常用的移動(dòng)端插件有 swiper、superslide、iscroll等。

框架: 大而全,一整套解決方案

插件: 小而專一,某個(gè)功能的解決方案

Bootstrap

Bootstrap 是一個(gè)簡(jiǎn)潔、直觀、強(qiáng)悍的前端開(kāi)發(fā)框架,它讓 web 開(kāi)發(fā)更迅速、簡(jiǎn)單。
它能開(kāi)發(fā)PC端,也能開(kāi)發(fā)移動(dòng)端
Bootstrap JS插件使用步驟:
1.引入相關(guān)js 文件
2.復(fù)制HTML 結(jié)構(gòu)
3.修改對(duì)應(yīng)樣式
4.修改相應(yīng)JS 參數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容