這是我參與更文挑戰的第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
文件就可使用該組件。
😀😀 關注我,不迷路! 😀😀