1.如何禁止用户在移动端的缩放
答:user-scalable设置为”no”; 如下代码
<meta
name="viewport"
id="view"
content="width=device-width, initial-scale=1, minimum-scale=1, user-scalable=no"
/>
2.如何使用js监听页面宽度的变化
答:监听window的”resize”方法;代码如下
window.addEventListener("resize", function() {
function refresh() {
let devicewidth = document.documentElement.clientWidth;
if (devicewidth > 1200) {
// document.documentElement.style.fontSize = 1200 / 12 + "px";
} else {
// document.documentElement.style.fontSize = devicewidth / 7.5 + "px"; //设计稿物理分辨率(750)/100
}
}
setTimeout(function() {
refresh();
}, 10);
});
3.如何自己实现一个弹出层
答:首先对弹出层设计分层,蒙层为全屏的父容器,弹出层的内容区域要水平垂直居中,要设计关闭的按钮。主要涉及到的知识点:
- css->position->absolute;
- css->z-index的运用,使弹出层居于最顶层
- css->实现水平垂直居中的方式
- js->添加事件监听,动态修改容器的style->display: none;达到隐藏弹出层的效果
具体代码如下:
<style>
#modal-container {
width: 100%;
height: 100%;
position: absolute;
/* justify-content: center;
align-items: center; */
z-index: 9999;
background-color: cadetblue;
top: 0;
left: 0;
display: none;
}
.modal {
width: 400px;
height: 300px;
border: 1px solid red;
/* margin: auto; */
position: absolute;
top: calc(50% - 150px);
left: calc(50% - 200px);
}
</style>
<body>
<div id="modal-container">
<div class="modal">
<div>I am Modal</div>
<button onclick="hideModal()">close me</button>
</div>
</div>
</body>
<script>
function hideModal() {
let modalC = document.getElementById("modal-container");
modalC.style.display = "none";
}
function showModal() {
let modalC = document.getElementById("modal-container");
modalC.style.display = "flex";
}
</script>
其中水平垂直居中的实现方式有以下常用的三种:(摘自)
1.display: flex
+ margin: auto
不限定宽高
<style>
main{
width: 100%;
min-height: 152px;
display: flex;
border:1rem solid red;
}
main > span {
background: #b4a078;
color: white;
margin: auto;
padding: .3em 1em .5em;
border-radius: 3px;
box-shadow: 0 0 .5em #b4a078;
}
</style>
<template>
<main>
<span>Center me, please!</span>
</main>
</template>
2.display: grid
不限定宽高
<style>
main{
width: 100%;
min-height: 152px;
display: grid;
justify-content: center;
align-items: center;
border:1rem solid red;
}
main > span {
background: #b4a078;
color: white;
padding: .3em 1em .5em;
border-radius: 3px;
box-shadow: 0 0 .5em #b4a078;
}
</style>
<template>
<main>
<span>Center me, please!</span>
</main>
</template>
3.绝对定位 position: absolute
+ calc()
限定宽高
<style>
main{
width: 100%;
min-height: 152px;
display: flex;
}
main > span {
position: absolute;
top: calc(50% - 16px);
left: calc(50% - 72px);
background: #b4a078;
color: white;
padding: .3em 1em .5em;
border-radius: 3px;
box-shadow: 0 0 .5em #b4a078;
}
</style>
<template>
<main>
<span>Center me, please!</span>
</main>
</template>
4.如何设置不透明度(摘自)
答:css->opacity属性
<style>
.transparent_class {
filter:alpha(opacity=50);//标准的css透明度,在大部分的标准浏览器Firefox, Safari, and Opera都有效
opacity:0.5;//兼容IE解决方案
-moz-opacity:0.5;//老的Mozilla browsers如NetscapeNavigator.几乎没有可以不需要
-khtml-opacity:0.5;//兼容老的Safari (1.x) 版本,很少可以不用
}
</style
箭头函数的特殊性
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。—— MDN
箭头函数没有自己的this
,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this
,并继承这个this
值。所以,箭头函数中this
的指向在它被定义的时候就已经确定了,之后永远不会改变。
.call()
/.apply()
/.bind()
方法可以用来动态修改函数执行时this
的指向,但由于箭头函数的this
定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this
的指向,虽然这么做代码不会报错。
事件捕获(event capture)、事件冒泡(event bubbling)、事件委托(event agent)
捕获阶段
是指从用户交互开始接触视图层,从最顶层的document元素开始一层的往下层穿透的过程。
冒泡阶段
是指当事件被捕获之后,从最内层子元素一层层往上穿透的过程。
阻止事件冒泡: e.stopPropagation();可以阻止子元素的时间冒泡的父元素层。
事件委托(代理模式)
场景:
需求:
方案:
- 传统的方式
const lis = document.getElementsByTagName("li");
for(li of lis){
li.addEventListener("click",function(e){
alert(e.target.innerHTML);
},false);
}
这种方式的缺点就是当数量很大的时候,就会很耗损性能,因为需要给每一个li元素绑定事件。
- 事件委托
const wrapper = document.getElementById("warapper");
warapper.addEventListener("click",function(e){
alert(e.target.innerHTML);
},false);
这里就是事件委托的解决方式,只给wrapper容器组件添加一个click事件,然后因为事件冒泡的机制,点击wrapper内的li的click事件最终会冒泡到wrapper事件内。
- tips👉: addEventListener方法的文档说明,看了之后,为什么第三位参数传递false。(监听模式)
- capture phase捕获阶段
- target phase 命中阶段
- bubbling phase 冒泡阶段
一道面试题(数组转化为树结构)
const arr = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 1 },
{ id: 4, pid: 2 },
{ id: 5, pid: 2 },
{ id: 6, pid: 3 },
{ id: 7, pid: 3 },
{ id: 8, pid: 3 },
{ id: 9, pid: 8 },
{ id: 10, pid: 6 }
];
function arr2tree(arr = []) {
let rootNode = arr.find(v => v.pid === null);
if (!rootNode) {
throw new Error("Expected rootNode not exists");
}
let rootNodeIndex = arr.findIndex(v => v.pid === null);
arr.splice(rootNodeIndex, 1);
let tree = {
id: rootNode.id,
children: []
};
let map = {};
arr.forEach(v => {
if (!map[v.pid]) {
map[v.pid] = [];
}
map[v.pid].push(v);
});
for (const pid in map) {
let children = map[pid];
children.forEach(child => {
if (map[child.id]) {
child.children = map[child.id];
}
});
}
tree.children = map[rootNode.id];
return tree;
}
const tree = arr2tree(arr);
方法2:递归调用
const arr = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 1 },
{ id: 4, pid: 2 },
{ id: 5, pid: 2 },
{ id: 6, pid: 3 },
{ id: 7, pid: 3 },
{ id: 8, pid: 3 },
{ id: 9, pid: 8 },
{ id: 10, pid: 6 }
];
function arr2tree(arr = []) {
let rootNode = arr.find(v => v.pid === null);
if (!rootNode) {
throw new Error("Expected rootNode not exists");
}
let rootNodeIndex = arr.findIndex(v => v.pid === null);
arr.splice(rootNodeIndex, 1);
let tree = {
id: rootNode.id,
children: []
};
let map = {};
arr.forEach(v => {
if (!map[v.pid]) {
map[v.pid] = [];
}
map[v.pid].push(v);
});
tree.children = map[rootNode.id];
function findChildren(node) {
if (map[node.id]) {
node.children = map[node.id];
node.children.forEach(n => findChildren(n));
}
}
tree.children.forEach(node => findChildren(node));
return tree;
}
const tree = arr2tree(arr);
console.log(JSON.stringify(tree));