1.如何禁止用户在移动端的缩放
答:user-scalable设置为”no”; 如下代码
<metaname="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));
