es--module模块

一、初识Module

模块:一个一个的局部作用域的代码块

 模块系统需要解决的主要问题:

        ① 模块化的问题

        ② 消除全局变量

        ③ 管理加载顺序

Module的基本用法: 

import、export:

只要你会用到 import(导入) 或 export(导出),在使用 script 标签加载的时候,就要加上 type="module"  

示例:

<div class="slider-layout">
        <div class="slider">
            <div class="slider-content">
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/1.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/2.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/3.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/4.jpg" alt="1" class="slider-img" /></a>
                </div>
            </div>
        </div>
    </div>

<script src="./index.js" type="module"></script>
/* css reset */
* {
  padding: 0;
  margin: 0;
}
a {
  text-decoration: none;
  outline: none;
}
img {
  vertical-align: top;
}

/* layout */
.slider-layout {
  width: 80%;
  height: 420px;
  margin: 0 auto;
}

/* slider */
.slider,
.slider-content,
.slider-item,
.slider-img {
  width: 100%;
  height: 100%;
}
.slider {
  overflow: hidden;
}
.slider-item {
  float: left;
}
.slider-animation {
  transition-property: transform;
  transition-duration: 0ms;
}
//base.js
// 默认参数
const DEFAULTS = {
    // 初始索引
    initialIndex: 0,
    // 切换时是否有动画
    animation: true,
    // 切换速度,单位 ms
    speed: 300
};
// base
const ELEMENT_NODE = 1;
const SLIDER_ANIMATION_CLASSNAME = 'slider-animation';

// 父类
class BaseSlider {
    constructor(el, options) {
        if (el.nodeType !== ELEMENT_NODE)
            throw new Error('实例化的时候,请传入 DOM 元素!');

        // 实际参数
        this.options = {
            ...DEFAULTS,
            ...options
        };

        const slider = el;
        const sliderContent = slider.querySelector('.slider-content');
        const sliderItems = sliderContent.querySelectorAll('.slider-item');

        // 添加到 this 上,为了在方法中使用
        this.slider = slider;
        this.sliderContent = sliderContent;
        this.sliderItems = sliderItems;

        this.minIndex = 0;
        this.maxIndex = sliderItems.length - 1;
        this.currIndex = this.getCorrectedIndex(this.options.initialIndex);

        // 每个 slider-item 的宽度(每次移动的距离)
        this.itemWidth = sliderItems[0].offsetWidth;

        this.init();
    }

    // 获取修正后的索引值
    // 随心所欲,不逾矩
    getCorrectedIndex(index) {
        if (index < this.minIndex) return this.maxIndex;
        if (index > this.maxIndex) return this.minIndex;
        return index;
    }

    // 初始化
    init() {
        // 为每个 slider-item 设置宽度
        this.setItemsWidth();

        // 为 slider-content 设置宽度
        this.setContentWidth();

        // 切换到初始索引 initialIndex
        this.move(this.getDistance());

        // 开启动画
        if (this.options.animation) {
            this.openAnimation();
        }
    }

    // 为每个 slider-item 设置宽度
    setItemsWidth() {
        for (const item of this.sliderItems) {
            item.style.width = `${this.itemWidth}px`;
        }
    }

    // 为 slider-content 设置宽度
    setContentWidth() {
        this.sliderContent.style.width = `${
      this.itemWidth * this.sliderItems.length
    }px`;
    }

    // 不带动画的移动
    move(distance) {
        this.sliderContent.style.transform = `translate3d(${distance}px, 0px, 0px)`;
    }

    // 带动画的移动
    moveWithAnimation(distance) {
        this.setAnimationSpeed(this.options.speed);
        this.move(distance);
    }

    // 设置切换动画速度
    setAnimationSpeed(speed) {
        this.sliderContent.style.transitionDuration = `${speed}ms`;
    }

    // 获取要移动的距离
    getDistance(index = this.currIndex) {
        return -this.itemWidth * index;
    }

    // 开启动画
    openAnimation() {
        this.sliderContent.classList.add(SLIDER_ANIMATION_CLASSNAME);
    }

    // 关闭动画
    closeAnimation() {
        this.setAnimationSpeed(0);
    }

    // 切换到 index 索引对应的幻灯片
    to(index) {
        index = this.getCorrectedIndex(index);
        if (this.currIndex === index) return;

        this.currIndex = index;
        const distance = this.getDistance();

        if (this.options.animation) {
            return this.moveWithAnimation(distance);
        } else {
            return this.move(distance);
        }
    }

    // 切换上一张
    prev() {
        this.to(this.currIndex - 1);
    }

    // 切换下一张
    next() {
        this.to(this.currIndex + 1);
    }

    // 获取当前索引
    getCurrIndex() {
        return this.currIndex;
    }
}
//导出--便于外面文件的访问
export default BaseSlider;
//slider.js
//导入
import BaseSlider from './base.js';

class Slider extends BaseSlider {
    constructor(el, options) {
        super(el, options);
        this._bindEvent();
    }

    _bindEvent() {
        document.addEventListener(
            'keyup',
            ev => {
                if (ev.keyCode === 37) {
                    this.prev();
                } else if (ev.keyCode === 39) {
                    this.next();
                }
            },
            false
        );
    }
}

export default Slider;
//index.js
import Slider from './slider.js';

new Slider(document.querySelector('.slider'));

当你按键盘上的左右按钮进行切换时:

二、 Module的导入导出

 1.export default导出和对应的import导入

导出的东西可以被导入(import),并访问到

一个模块没有导出,也可以将其导入

被导入的代码都会执行一遍,也仅会执行一遍

import './module.js';

示例:

<script type="module">


        import './module.js';
</script>
const age = 18;
// const sex = 'male';
console.log(age);

一个模块只能有一个 export default

export default 名;//导出

import 名 from '文件路径';//导入

示例:

<script type="module">
     import age from './module.js'; 
     console.log(age);
</script>
const sex = 'male';


// 一个模块只能有一个 export default
export default sex;

2.export导出和对应的import导入

a.基本用法:

语法:export  声明或语句

export  const age = 18;

 <script type="module">
        //切记:不能随意命名
        import {age} from './module.js'; 
        console.log(age);
</script>
//方式1
export const age = 18;

//方式2:
const age = 18;
// export age; ×
export { age }; // √

b.导出、导入多个

       //导入方式1
        // import {fn} from './module.js'; 
        // console.log(fn); 
        // import {className} from './module.js'; 
        // console.log(className);
        // import {age} from './module.js'; 
        // console.log(age);

       //导入方式2
      import { fn, age, className } from './module.js'; 
      console.log(fn, age, className);
function fn() {};
//export function fn() {}; //导出方式1
// export function () {} // 匿名函数不行
// export { fn }; //导出方式2

class className {}
// export { className }; //导出方式2

// export class className {}//导出方式1
// export class  {} // 匿名不行

// export const age = 18;//导出方式1
const age = 18;
// export { age };

export { fn, className, age }; //导出方式3

c.导出导入时起别名

<script type="module">

        import { func, age, className as person } from './module.js'; console.log(func, age, person);

</script>
function fn() {};
//export function fn() {}; //导出方式1
// export function () {} // 匿名函数不行
// export { fn }; //导出方式2

class className {}
// export { className }; //导出方式2

// export class className {}//导出方式1
// export class  {} // 匿名不行

// export const age = 18;//导出方式1
const age = 18;
// export { age };

export { fn as func, className, age }; //导出方式3

d.整体导入

会导入所有输出,包括通过 export default 导出的

 <script type="module">

        import * as obj from './module.js'; console.log(obj);

</script>
function fn() {};
//export function fn() {}; //导出方式1
// export function () {} // 匿名函数不行
// export { fn }; //导出方式2

class className {}
// export { className }; //导出方式2

// export class className {}//导出方式1
// export class  {} // 匿名不行

// export const age = 18;//导出方式1
const age = 18;
// export { age };

export { fn as func, className, age }; //导出方式3

export default 18;

e.同时导入

注意:一定是 export default 的在前


    <script type="module">

        import age2, { func, age, className } from './module.js'; console.log(age2);

    </script>
function fn() {};
//export function fn() {}; //导出方式1
// export function () {} // 匿名函数不行
// export { fn }; //导出方式2

class className {}
// export { className }; //导出方式2

// export class className {}//导出方式1
// export class  {} // 匿名不行

// export const age = 18;//导出方式1
const age = 18;
// export { age };

export { fn as func, className, age }; //导出方式3

export default 18;

三、Module的注意事项和应用

1.注意事项

a.模块顶层的 this 指向

模块中,顶层的 this 指向 undefined

import './module.js';

<script type="module">
        import './module.js';
</script>或
<script src="./module.js" type="module"></script> 
console.log(this);
//这里的顶层指的是不在if、for这样的块级作用域中或者不在function这样的函数作用域中,而是在模块最顶层的作用域中

b.import关键字 和 import()函数

import关键字 命令具有提升效果,会提升到整个模块的头部,率先执行

<script type="module">
        console.log('沙发'); 
        console.log('第二'); 
        import './module.js';
</script>
console.log(this);

注意:

  • import 执行的时候,代码还没执行
  • import 和 export 命令只能在模块的顶层,不能在代码块中执行

     //错误

        if (PC) {

        import 'pc.js';

      } else if (Mobile) {

        import 'mobile.js';

      }

import() 可以按条件导入

if (PC) {//将import关键字改为import()函数

        import('pc.js').then().catch();

      } else if (Mobile) {

        import('mobile.js').then().catch();

      }

c.导入导出的复合写法

复合写法导出的,无法在当前模块中使用

<script type="module">

        export { age } from './module.js'; 
        console.log(age);

         // 等价于
        // import { age } from './module.js';
        // export { age } from './module.js';
        // console.log(age);

</script>
export const age = 18;

2.应用

<div class="slider-layout">
        <div class="slider">
            <div class="slider-content">
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/1.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/2.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/3.jpg" alt="1" class="slider-img" /></a>
                </div>
                <div class="slider-item">
                    <a href="javascript:;"><img src="./imgs/4.jpg" alt="1" class="slider-img" /></a>
                </div>
            </div>
        </div>
    </div>

    <script src="./index.js" type="module"></script>
/* css reset */
* {
  padding: 0;
  margin: 0;
}
a {
  text-decoration: none;
  outline: none;
}
img {
  vertical-align: top;
}

/* layout */
.slider-layout {
  width: 80%;
  height: 420px;
  margin: 0 auto;
}

/* slider */
.slider,
.slider-content,
.slider-item,
.slider-img {
  width: 100%;
  height: 100%;
}
.slider {
  overflow: hidden;
}
.slider-item {
  float: left;
}
.slider-animation {
  transition-property: transform;
  transition-duration: 0ms;
}
//index.js
import Slider from './slider.js';

new Slider(document.querySelector('.slider'));
//slider.js
import BaseSlider from './base.js';
import Keyboard from './keyboard.js';
// import Mouse from './mouse.js';

class Slider extends BaseSlider {
    constructor(el, options) {
        super(el, options);
        this._bindEvent();
    }

    _bindEvent() {
        Keyboard.bindEvent(this);
        // Mouse.bindEvent(this);
    }
}

export default Slider;
//base.js
// 默认参数
import DEFAULTS from './defaults.js';

// 常量
import { ELEMENT_NODE, SLIDER_ANIMATION_CLASSNAME } from './constants.js';

class BaseSlider {
  constructor(el, options) {
    if (el.nodeType !== ELEMENT_NODE)
      throw new Error('实例化的时候,请传入 DOM 元素!');

    // 实际参数
    this.options = {
      ...DEFAULTS,
      ...options
    };

    const slider = el;
    const sliderContent = slider.querySelector('.slider-content');
    const sliderItems = sliderContent.querySelectorAll('.slider-item');

    // 添加到 this 上,为了在方法中使用
    this.slider = slider;
    this.sliderContent = sliderContent;
    this.sliderItems = sliderItems;

    this.minIndex = 0;
    this.maxIndex = sliderItems.length - 1;
    this.currIndex = this.getCorrectedIndex(this.options.initialIndex);

    // 每个 slider-item 的宽度(每次移动的距离)
    this.itemWidth = sliderItems[0].offsetWidth;

    this.init();
  }

  // 获取修正后的索引值
  // 随心所欲,不逾矩
  getCorrectedIndex(index) {
    if (index < this.minIndex) return this.maxIndex;
    if (index > this.maxIndex) return this.minIndex;
    return index;
  }

  // 初始化
  init() {
    // 为每个 slider-item 设置宽度
    this.setItemsWidth();

    // 为 slider-content 设置宽度
    this.setContentWidth();

    // 切换到初始索引 initialIndex
    this.move(this.getDistance());

    // 开启动画
    if (this.options.animation) {
      this.openAnimation();
    }
  }

  // 为每个 slider-item 设置宽度
  setItemsWidth() {
    for (const item of this.sliderItems) {
      item.style.width = `${this.itemWidth}px`;
    }
  }

  // 为 slider-content 设置宽度
  setContentWidth() {
    this.sliderContent.style.width = `${
      this.itemWidth * this.sliderItems.length
    }px`;
  }

  // 不带动画的移动
  move(distance) {
    this.sliderContent.style.transform = `translate3d(${distance}px, 0px, 0px)`;
  }

  // 带动画的移动
  moveWithAnimation(distance) {
    this.setAnimationSpeed(this.options.speed);
    this.move(distance);
  }

  // 设置切换动画速度
  setAnimationSpeed(speed) {
    this.sliderContent.style.transitionDuration = `${speed}ms`;
  }

  // 获取要移动的距离
  getDistance(index = this.currIndex) {
    return -this.itemWidth * index;
  }

  // 开启动画
  openAnimation() {
    this.sliderContent.classList.add(SLIDER_ANIMATION_CLASSNAME);
  }

  // 关闭动画
  closeAnimation() {
    this.setAnimationSpeed(0);
  }

  // 切换到 index 索引对应的幻灯片
  to(index) {
    index = this.getCorrectedIndex(index);
    if (this.currIndex === index) return;

    this.currIndex = index;
    const distance = this.getDistance();

    if (this.options.animation) {
      return this.moveWithAnimation(distance);
    } else {
      return this.move(distance);
    }
  }

  // 切换上一张
  prev() {
    this.to(this.currIndex - 1);
  }

  // 切换下一张
  next() {
    this.to(this.currIndex + 1);
  }

  // 获取当前索引
  getCurrIndex() {
    return this.currIndex;
  }
}

export default BaseSlider;
//defaults.js
// 默认参数
// const DEFAULTS = {
//   // 初始索引
//   initialIndex: 0,
//   // 切换时是否有动画
//   animation: true,
//   // 切换速度,单位 ms
//   speed: 300
// };

// export default DEFAULTS;

export default {
  // 初始索引
  initialIndex: 0,
  // 切换时是否有动画
  animation: true,
  // 切换速度,单位 ms
  speed: 300
};
//keyboard.js
import { LEFT_KEYCODE, RIGHT_KEYCODE } from './constants.js';

const keyboard = {
  bindEvent(slider) {
    document.addEventListener(
      'keyup',
      ev => {
        if (ev.keyCode === LEFT_KEYCODE) {
          slider.prev();
        } else if (ev.keyCode === RIGHT_KEYCODE) {
          slider.next();
        }
      },
      false
    );
  }
};

export default keyboard;
//constants.js
// base
export const ELEMENT_NODE = 1;
export const SLIDER_ANIMATION_CLASSNAME = 'slider-animation';

// keyboard
export const LEFT_KEYCODE = 37;
export const RIGHT_KEYCODE = 39;

当单击键盘上的左右箭头时:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白小白从不日白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值