Cap1 前言
这几天投了几家上海的公司,有一家公司给我面试题是这样的:
说实话倒是不难,以前在开发移动端时候做过类似的。但主要是要求复用性,所以想法单独抽取一个库然后暴露插件能力即可。
Cap2 环境
除了弹窗需要原生语言实现,环境可以使用 nodejs 技术栈实现:
npm init # 初始化项目
npm i @babel/core @babel/preset-env babel-loader --dev-save
npm i webpack webpack-cli webpack-node-externals --dev-save
目前就简单实现下:
Babel 是方便把项目其中的 ES6 代码转换成浏览器可读的 JavaScript 代码,而webpack是将项目打包成 JavaScript 库。打包效果和 jQuery 差不多,引入 jQuery 库文件就可以使用相关方法,所以根据 Webpack 文档说明,配置下 webpack.config.babel.js
文件:
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
target: 'node',
mode: 'production',
entry: {
index: './src/index.js'
},
externals: [nodeExternals()],
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js',
library: 'Overlay',
libraryTarget: 'var'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
},
devtool: 'source-map'
};
上述代码中output
中的library
是暴露库文件的能力,所以这里设定和 jQuery 命名一样的Overlay
。同样要注意libraryTarget
:
var
默认值,暴露一个变量,通过对象上赋值暴露,一般用于浏览器环境。commonjs2
模块定义系统,适用于 node 环境。amd
模块定义系统,适用于浏览器环境下的 RequireJS 模块。
然后可以在package.json
中scripts
字段添加:
"build": "webpack --progress --color",
可以编译 JavaScript 库文件了:
打开src/index.js
:
console.log('hello world');
最后编译的文件在dist/index.js
,新建个 html 引入打开控制台就可以看到输出了。
Cap3 弹窗实现
其实弹窗实现很简单,无非俩个dom点击事件,我的思路就是直接插入弹窗的DOM数据就行了,所以遇到一个比较麻烦的问题,如何使用插入DOM数据?其实完全可以利用原生 JavaScript 中的 appendChild
方法,传入是NodeLIst 对象,我当时直接用 String,所以后面报错了:
/**
* 将字符串转换DOM对象
* @param str 传入值
* @returns {NodeListOf<ChildNode>} node list对象
*/
const parseDom = (str) => {
const obj = document.createElement('div')
obj.className = 'overlay-wrapper'
obj.innerHTML = str
return obj
}
export const full = ( options = {} ) => {
const div = '' // 弹窗内容,具体请到github查看
// 写入dom
document.querySelector('body').appendChild(parseDom(div));
// 点击确定按钮
document.querySelector('.overlay-box-button-confirm').addEventListener('click', function () {
document.querySelector('.overlay-wrapper').remove(); // 删除dom
options.confirm();
});
// 点击取消按钮
document.querySelector('.overlay-box-button-cancel').addEventListener('click', function () {
document.querySelector('.overlay-wrapper').remove(); // 删除dom
options.cancel();
});
}
所以使用方法:
Overlay.full({
title: '你好', // 弹窗标题
content: '世界', // 弹窗内容
confirm: function () {
console.log('确定')
}, // 点击确定回调事件
cancel: function () {
console.log('取消')
} // 点击取消回调事件
})
css样式:
.overlay-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
text-align: center;
z-index: 2010;
background-color: rgba(0, 0, 0, .7);
}
.overlay-wrapper::after {
content: "";
display: inline-block;
height: 100%;
width: 0;
vertical-align: middle;
}
.overlay-box {
display: inline-block;
width: 420px;
padding-bottom: 10px;
vertical-align: middle;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ebeef5;
font-size: 18px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
text-align: left;
overflow: hidden;
backface-visibility: hidden;
}
@media all and (max-width:719px){
.overlay-box {
width: 300px;
}
}
.overlay-box-header {
position: relative;
padding: 15px;
padding-bottom: 10px;
}
.overlay-box-content {
position: relative;
padding: 10px 15px;
color: #606266;
font-size: 14px;
}
.overlay-box-footer {
padding: 5px 15px 0;
text-align: right;
}
.overlay-box-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 9px 15px;
font-size: 12px;
border-radius: 3px;
}
.overlay-box-button-primary {
color: #fff;
background-color: #409EFF;
border-color: #409EFF;
}
.overlay-box-button-cancel {
color: #409EFF;
background-color: #fff;
border-color: #409EFF;
}