这是我参与更文挑战的第8天,活动详情查看: 更文挑战javascript
在上一篇文章中,咱们讲述了什么是组件,与开发一个组件须要用到些什么工具,以后又带领着你们把原有的webpack-template
的目录结构和配置文件进行了一些小改动,接下来这一期将把组件引进到模板中以及如何去调试配置咱们的组件 ~ ~css
若是尚未阅读第一篇的小伙伴们,请点击阅读手把手教你使用webpack打包前端组件(一)html
回到咱们在上一篇文章中建立的src / components / better-draggable-ball / index.ts
文件,把以前写好的插件代码粘贴入进去前端
// 插件代码
interface DefaultPositionType {
x?: number,
y?: number
}
interface Options {
autoAdsorbent?: boolean;
hideOffset?: number;
defaultPosition?: DefaultPositionType;
}
export default class Drag {
// 元素
element: HTMLElement;
// 屏幕尺寸
screenWidth: number;
screenHeight: number;
// 元素大小
elementWidth: number;
elementHeight: number;
isPhone: boolean;
// 当前元素坐标
elementX: number;
elementY: number;
// 元素offset
elementOffsetX: number;
elementOffsetY: number;
// 是否处于拖动状态
moving: boolean;
// 吸附
autoAdsorbent: boolean;
// 隐藏
hideOffset: number;
constructor(element: HTMLElement, dConfig: Options = {}) {
dConfig = this.InitParams(dConfig);
this.element = element;
this.screenWidth = window.innerWidth || window.outerWidth || 0;
this.screenHeight = window.innerHeight || window.outerHeight || 0;
this.elementWidth = this.element.offsetWidth || 0;
this.elementHeight = this.element.offsetHeight || 0;
this.isPhone = /(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent);
this.element.style.position = 'absolute';
this.elementX = 0;
this.elementY = 0;
this.elementOffsetX = 0;
this.elementOffsetY = 0;
this.moving = false;
this.autoAdsorbent = dConfig.autoAdsorbent;
this.hideOffset = this.elementWidth * dConfig.hideOffset;
if (!this.isPhone) {
console.error('警告!!当前插件版本只兼容移动端');
}
// 默认位置
this.setElementPosition(dConfig.defaultPosition.x, dConfig.defaultPosition.y);
this.watchTouch();
}
protected InitParams(dConfig: Options):Options {
// 处理下Options未配置的参数
return {
autoAdsorbent: dConfig.autoAdsorbent || false,
hideOffset: dConfig.hideOffset || 0,
defaultPosition: dConfig.defaultPosition || { x: 0, y: 0 },
};
}
private watchTouch(): void {
this.element.addEventListener('touchstart', (event: TouchEvent) => {
const rect = (event.target as HTMLElement).getBoundingClientRect();
// 页面被卷去的高度
// 不兼容IE
const docScrollTop = document.documentElement.scrollTop;
this.elementOffsetX = event.targetTouches[0].pageX - rect.left;
this.elementOffsetY = event.targetTouches[0].pageY - rect.top - docScrollTop;
this.moving = true;
this.element.addEventListener('touchmove', this.move.bind(this), { passive: false });
});
window.addEventListener('touchend', () => {
this.moving = false;
document.removeEventListener('touchmove', this.move);
if (this.autoAdsorbent) this.adsorbent();
});
}
private setElementPosition(x: number, y: number): void {
// 溢出处理
// 溢出范围
// 但页面超出屏幕范围,计算当前屏幕范围
const leftScope = this.moving ? 0 : 0 - this.hideOffset;
// 当前屏幕right最大值
const rs = this.screenWidth - this.elementWidth;
const rightScope = this.moving ? rs : rs + this.hideOffset;
const bottomScope = this.screenHeight - this.elementHeight;
if (x <= leftScope && y <= 0) {
[x, y] = [leftScope, 0];
} else if (x >= rightScope && y <= 0) {
[x, y] = [rightScope, 0];
} else if (x <= leftScope && y >= bottomScope) {
[x, y] = [leftScope, bottomScope];
} else if (x >= rightScope && y >= bottomScope) {
[x, y] = [rightScope, bottomScope];
} else if (x > rightScope) {
x = rightScope;
} else if (y > bottomScope) {
y = bottomScope;
} else if (x <= leftScope) {
x = leftScope;
} else if (y <= 0) {
y = 0;
}
this.elementX = x;
this.elementY = y;
this.element.style.top = `${y}px`;
this.element.style.left = `${x}px`;
}
private move(event: TouchEvent): void {
event.preventDefault();
if (!this.moving) return;
this.elementY = (event.touches[0].pageX - this.elementOffsetX);
this.elementX = (event.touches[0].pageY - this.elementOffsetY);
const ex = (event.touches[0].pageX - this.elementOffsetX);
const ey = (event.touches[0].pageY - this.elementOffsetY);
this.setElementPosition(ex, ey);
}
private animate(targetLeft: number, spd: number): void {
const timer = setInterval(() => {
let step = (targetLeft - this.elementX) / 10;
// 对步长进行二次加工(大于0向上取整,小于0向下取整)
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// 动画原理: 目标位置 = 当前位置 + 步长
const x = this.elementX + step;
this.setElementPosition(x, this.elementY);
// 检测缓动动画有没有中止
if (Math.abs(targetLeft - this.elementX) <= Math.abs(step)) {
// 处理小数赋值
const xt = targetLeft;
this.setElementPosition(xt, this.elementY);
clearInterval(timer);
}
}, spd);
}
private adsorbent():void {
// 判断吸附方向
// 屏幕中心点
const screenCenterY = Math.round(this.screenWidth / 2);
// left 最大值
const rightScope = this.screenWidth - this.elementWidth;
// 根据中心点来判断吸附方向
if (this.elementX < screenCenterY) {
this.animate(0 - (this.hideOffset), 10);
} else {
this.animate(rightScope + (this.hideOffset), 10);
}
}
}
复制代码
在组件开发的过程当中每每少不了对组件的功能调试以及样式的展现,这时可使用webpack-dev-server
这个插件,它给咱们提供了一个基本的web server
,而且具备实时从新更新页面的功能。java
安装 webpack-dev-server
node
npm install --save-dev webpack-dev-server
复制代码
!这里只是先安装,稍后咱们将在配置文件中配置使用它webpack
咱们在pages
文件夹下新建Drag
的页面以及它的ts
,scss
文件,用来调试组件:程序员
Drag
页面内容分别为:web
// Drag.html
<!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">
<title>Drag</title>
</head>
<body>
<h2>
Drag.html
</h2>
</body>
</html>
复制代码
// Drag.scss
*{
margin: 0;
padding: 0;
}
body{
padding: 20px;
}
#drag{
width: 50px;
height: 50px;
background-color: rgb(238, 238, 238);
border-radius: 50%;
border: 5px solid rgb(170, 170, 170);
}
p{
height: 50px;
}
复制代码
//Drag.ts
import './Drag.scss';
import Drag from '../../components/better-draggable-ball/index';
const dragDom = document.createElement('div');
dragDom.setAttribute('id', 'drag');
const body = document.getElementsByTagName('body')[0];
body.appendChild(dragDom);
new Drag(dragDom, {
defaultPosition: { x: 10, y: 10 },
autoAdsorbent: true,
});
复制代码
把项目的根目录下的webpack.config.ts
文件复制多一份出来,命名为webpack.config.dev.ts
,这个文件只要用于调试时使用。typescript
修改webpack.config.dev.ts
文件:
在配置类型方面,咱们须要作出一些修改,本来咱们的配置对象模块中用的是webpack
包中的config
类型,但如今咱们须要用到另一个模块(webpack-dev-server
)要在配置对象中配置devServer
属性,而webpack
中的config
中没有devServer
这个类型的属性,咱们定义一个Configuration
接口做为配置文件的类型,让它继承下webpack
包中的config
,当它底下有devServer
的时候则对应上WebpackDevServerConfiguration
// webpack.config.dev.ts
import { Configuration as webpackConfiguration } from 'webpack';
import {Configuration as WebpackDevServerConfiguration} from 'webpack-dev-server';
interface Configuration extends webpackConfiguration{
devServer ?: WebpackDevServerConfiguration;
}
复制代码
加入devServer
属性,配置运行目录和服务接口,这里compress
指的是代码是否启用GZIP压缩:
const config: Configuration = {
// 忽略一些代码
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
},
}
复制代码
在entry
和plugins
属性中新增Drag页面
// webpack.config.dev.ts
entry: {
// 忽略一些代码
Drag: './src/pages/Drag/Drag.ts', // Drag页面
},
复制代码
// webpack.config.dev.ts
new HtmlWebpackPlugin({
title: 'Drag',
filename: 'Drag.html',
template: './src/pages/Drag/Drag.html',
chunks: ['Drag', 'main'],
}),
复制代码
修改package.json
文件:
--config
参数是指定配置文件,若是没有指定默认是使用webpack.config.ts
文件
--open
参数是当服务启动完毕后,自动的将目标URL打开
"scripts": {
" ... 这里忽略了一些命令 ... "
"serve": "webpack serve --config webpack.dev.config.ts --open"
},
复制代码
为了方便你们CVCVCV
大法,我直接把整个webpack.config.dev.ts
贴上来哈哈,懒是程序员第一辈子产力。
// webpack.config.dev.ts
import * as path from 'path';
import { Configuration as webpackConfiguration } from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import {Configuration as WebpackDevServerConfiguration} from 'webpack-dev-server';
interface Configuration extends webpackConfiguration{
devServer ?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: 'production',
entry: {
main: './src/main.ts',
index: './src/pages/index/index.ts', // index页面
Drag: './src/pages/Drag/Drag.ts', // hello页面
'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: (pathData:any) => (pathData.chunk.name === 'better-draggable-ball' ? 'js/components/[name]/[name].js' : 'js/[name]/[name].js'),
clean: true,
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
// 将 Sass 编译成 CSS
'sass-loader',
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'index',
filename: 'index.html',
template: './src/pages/index/index.html',
chunks: ['index', 'main'],
}),
new HtmlWebpackPlugin({
title: 'Drag',
filename: 'Drag.html',
template: './src/pages/Drag/Drag.html',
chunks: ['Drag', 'main'],
}),
new ESLintPlugin({
extensions: ['js', 'ts'],
exclude: '/node_modules/',
}),
],
};
export default config;
复制代码
执行npm run serve
后,webserver
将开始运行构建一个服务环境,对应的URL
地址也在terminal
中显示出来,webserver
也会自动的帮咱们打开浏览器访问对应的URL
地址。
当这不是咱们想要Drag页面,如今有两种方法能够切换到Drag
页面中:
在浏览器中把URL路径修改成http://localhost:8080/Drag.html
在devserver
对象中,添加openPage
属性,让其页面自动的显示出来
devServer: {
openPage: 'Drag.html',
}
复制代码
再跑一下,浏览器自动的打开Drag页面,咱们的better-drag-ball
组件也显示了出来。
到了这里,咱们的组件的调试环境已经部署好了。
感谢你们的观看下一篇文章中咱们将这个组件进行一个多版本的输出打包,让用户直接引用javascript
文件就可使用该组件。
😀😀 关注我,不迷路! 😀😀