1.如何禁止用户在移动端的缩放

答:user-scalable设置为”no”; 如下代码

  1. <meta
  2. name="viewport"
  3. id="view"
  4. content="width=device-width, initial-scale=1, minimum-scale=1, user-scalable=no"
  5. />

2.如何使用js监听页面宽度的变化

答:监听window的”resize”方法;代码如下

  1. window.addEventListener("resize", function() {
  2. function refresh() {
  3. let devicewidth = document.documentElement.clientWidth;
  4. if (devicewidth > 1200) {
  5. // document.documentElement.style.fontSize = 1200 / 12 + "px";
  6. } else {
  7. // document.documentElement.style.fontSize = devicewidth / 7.5 + "px"; //设计稿物理分辨率(750)/100
  8. }
  9. }
  10. setTimeout(function() {
  11. refresh();
  12. }, 10);
  13. });

3.如何自己实现一个弹出层

答:首先对弹出层设计分层,蒙层为全屏的父容器,弹出层的内容区域要水平垂直居中,要设计关闭的按钮。主要涉及到的知识点:

  1. css->position->absolute;
  2. css->z-index的运用,使弹出层居于最顶层
  3. css->实现水平垂直居中的方式
  4. js->添加事件监听,动态修改容器的style->display: none;达到隐藏弹出层的效果

具体代码如下:

  1. <style>
  2. #modal-container {
  3. width: 100%;
  4. height: 100%;
  5. position: absolute;
  6. /* justify-content: center;
  7. align-items: center; */
  8. z-index: 9999;
  9. background-color: cadetblue;
  10. top: 0;
  11. left: 0;
  12. display: none;
  13. }
  14. .modal {
  15. width: 400px;
  16. height: 300px;
  17. border: 1px solid red;
  18. /* margin: auto; */
  19. position: absolute;
  20. top: calc(50% - 150px);
  21. left: calc(50% - 200px);
  22. }
  23. </style>
  24. <body>
  25. <div id="modal-container">
  26. <div class="modal">
  27. <div>I am Modal</div>
  28. <button onclick="hideModal()">close me</button>
  29. </div>
  30. </div>
  31. </body>
  32. <script>
  33. function hideModal() {
  34. let modalC = document.getElementById("modal-container");
  35. modalC.style.display = "none";
  36. }
  37. function showModal() {
  38. let modalC = document.getElementById("modal-container");
  39. modalC.style.display = "flex";
  40. }
  41. </script>

其中水平垂直居中的实现方式有以下常用的三种:(摘自)
1.display: flex + margin: auto 不限定宽高

  1. <style>
  2. main{
  3. width: 100%;
  4. min-height: 152px;
  5. display: flex;
  6. border:1rem solid red;
  7. }
  8. main > span {
  9. background: #b4a078;
  10. color: white;
  11. margin: auto;
  12. padding: .3em 1em .5em;
  13. border-radius: 3px;
  14. box-shadow: 0 0 .5em #b4a078;
  15. }
  16. </style>
  17. <template>
  18. <main>
  19. <span>Center me, please!</span>
  20. </main>
  21. </template>

2.display: grid 不限定宽高

  1. <style>
  2. main{
  3. width: 100%;
  4. min-height: 152px;
  5. display: grid;
  6. justify-content: center;
  7. align-items: center;
  8. border:1rem solid red;
  9. }
  10. main > span {
  11. background: #b4a078;
  12. color: white;
  13. padding: .3em 1em .5em;
  14. border-radius: 3px;
  15. box-shadow: 0 0 .5em #b4a078;
  16. }
  17. </style>
  18. <template>
  19. <main>
  20. <span>Center me, please!</span>
  21. </main>
  22. </template>

3.绝对定位 position: absolute + calc() 限定宽高

  1. <style>
  2. main{
  3. width: 100%;
  4. min-height: 152px;
  5. display: flex;
  6. }
  7. main > span {
  8. position: absolute;
  9. top: calc(50% - 16px);
  10. left: calc(50% - 72px);
  11. background: #b4a078;
  12. color: white;
  13. padding: .3em 1em .5em;
  14. border-radius: 3px;
  15. box-shadow: 0 0 .5em #b4a078;
  16. }
  17. </style>
  18. <template>
  19. <main>
  20. <span>Center me, please!</span>
  21. </main>
  22. </template>

4.如何设置不透明度(摘自)

答:css->opacity属性

  1. <style>
  2. .transparent_class {
  3. filter:alpha(opacity=50);//标准的css透明度,在大部分的标准浏览器Firefox, Safari, and Opera都有效
  4. opacity:0.5;//兼容IE解决方案
  5. -moz-opacity:0.5;//老的Mozilla browsers如NetscapeNavigator.几乎没有可以不需要
  6. -khtml-opacity:0.5;//兼容老的Safari (1.x) 版本,很少可以不用
  7. }
  8. </style

箭头函数的特殊性

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的thisargumentssupernew.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。—— MDN

箭头函数没有自己的this,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。

.call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向,虽然这么做代码不会报错。

事件捕获(event capture)、事件冒泡(event bubbling)、事件委托(event agent)

捕获阶段

是指从用户交互开始接触视图层,从最顶层的document元素开始一层的往下层穿透的过程。

冒泡阶段

是指当事件被捕获之后,从最内层子元素一层层往上穿透的过程。

阻止事件冒泡: e.stopPropagation();可以阻止子元素的时间冒泡的父元素层。

事件委托(代理模式)

场景:

一个wrapper容器内有10的n次方个li标签

需求:

点击每一个li标签都显示一下li里面的内容

方案:

  1. 传统的方式
  1. const lis = document.getElementsByTagName("li");
  2. for(li of lis){
  3. li.addEventListener("click",function(e){
  4. alert(e.target.innerHTML);
  5. },false);
  6. }

这种方式的缺点就是当数量很大的时候,就会很耗损性能,因为需要给每一个li元素绑定事件。

  1. 事件委托
  1. const wrapper = document.getElementById("warapper");
  2. warapper.addEventListener("click",function(e){
  3. alert(e.target.innerHTML);
  4. },false);

这里就是事件委托的解决方式,只给wrapper容器组件添加一个click事件,然后因为事件冒泡的机制,点击wrapper内的li的click事件最终会冒泡到wrapper事件内。

  1. tips👉: addEventListener方法的文档说明,看了之后,为什么第三位参数传递false。(监听模式

参考:事件流事件顺序
事件传递的三个阶段:

  1. capture phase捕获阶段
  2. target phase 命中阶段
  3. bubbling phase 冒泡阶段

一道面试题(数组转化为树结构)

  1. const arr = [
  2. { id: 1, pid: null },
  3. { id: 2, pid: 1 },
  4. { id: 3, pid: 1 },
  5. { id: 4, pid: 2 },
  6. { id: 5, pid: 2 },
  7. { id: 6, pid: 3 },
  8. { id: 7, pid: 3 },
  9. { id: 8, pid: 3 },
  10. { id: 9, pid: 8 },
  11. { id: 10, pid: 6 }
  12. ];
  13. function arr2tree(arr = []) {
  14. let rootNode = arr.find(v => v.pid === null);
  15. if (!rootNode) {
  16. throw new Error("Expected rootNode not exists");
  17. }
  18. let rootNodeIndex = arr.findIndex(v => v.pid === null);
  19. arr.splice(rootNodeIndex, 1);
  20. let tree = {
  21. id: rootNode.id,
  22. children: []
  23. };
  24. let map = {};
  25. arr.forEach(v => {
  26. if (!map[v.pid]) {
  27. map[v.pid] = [];
  28. }
  29. map[v.pid].push(v);
  30. });
  31. for (const pid in map) {
  32. let children = map[pid];
  33. children.forEach(child => {
  34. if (map[child.id]) {
  35. child.children = map[child.id];
  36. }
  37. });
  38. }
  39. tree.children = map[rootNode.id];
  40. return tree;
  41. }
  42. const tree = arr2tree(arr);

方法2:递归调用

  1. const arr = [
  2. { id: 1, pid: null },
  3. { id: 2, pid: 1 },
  4. { id: 3, pid: 1 },
  5. { id: 4, pid: 2 },
  6. { id: 5, pid: 2 },
  7. { id: 6, pid: 3 },
  8. { id: 7, pid: 3 },
  9. { id: 8, pid: 3 },
  10. { id: 9, pid: 8 },
  11. { id: 10, pid: 6 }
  12. ];
  13. function arr2tree(arr = []) {
  14. let rootNode = arr.find(v => v.pid === null);
  15. if (!rootNode) {
  16. throw new Error("Expected rootNode not exists");
  17. }
  18. let rootNodeIndex = arr.findIndex(v => v.pid === null);
  19. arr.splice(rootNodeIndex, 1);
  20. let tree = {
  21. id: rootNode.id,
  22. children: []
  23. };
  24. let map = {};
  25. arr.forEach(v => {
  26. if (!map[v.pid]) {
  27. map[v.pid] = [];
  28. }
  29. map[v.pid].push(v);
  30. });
  31. tree.children = map[rootNode.id];
  32. function findChildren(node) {
  33. if (map[node.id]) {
  34. node.children = map[node.id];
  35. node.children.forEach(n => findChildren(n));
  36. }
  37. }
  38. tree.children.forEach(node => findChildren(node));
  39. return tree;
  40. }
  41. const tree = arr2tree(arr);
  42. console.log(JSON.stringify(tree));