1.创意广告牌

.billboard {
  position: relative;
  background-color: #8e6534;
  color: #fff;
  padding: 20px;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.3);
  background-size: cover;
  /* TODO:待补充代码  设置圆角 10px,背景图片为woodiness.jpg  */
  background-image: url(../images/woodiness.jpg);
  border-radius: 10px;
}
.top-sign {
  position: relative;
  width: 200px;
  height: 100px;
  background-color: #a87f4a;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1rem;
  /* TODO:待补充代码   上面两个角是圆角 15px,下面两个角是直角  元素 x 轴倾斜 20度*/
 border-radius: 15px 15px 0px 0px ;
 transform: skewX(-20deg);

}

2原子化 CSS

/* TODO: 实现原子化 flex */
div {
  display: flex;
  flex-direction: column;
}

3神秘咒语 

TODO:新增或者修改以下代码

key1Button.addEventListener('click', async () => {
    // 从后台请求钥匙1的咒语部分
    key1Button.disabled = true;
    let {data} =  await axios.get('/spellone',{
        headers:{
            'Authorization':'2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7',
        }
    })
    spell1.innerHTML = data;
    tryOpenTreasureBox();
});

key2Button.addEventListener('click', async () => {
    // 从后台请求钥匙2的咒语部分
    key2Button.disabled = true;
    let {data} =  await axios.get('/spelltwo',{
        headers:{
            Authorization:'2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7',
        }
    })
    spell2.innerHTML = data;
    tryOpenTreasureBox();
});

4. 朋友圈

目标

请在 index.js 文件中补全代码,具体需求如下:

  1. 请将 debounce 函数补充完整,实现一个延迟为 delay 毫秒的防抖函数。
  2. 用户在输入框( id=text )输入文字时,将用户输入的内容存入 localStorage 中,缓存的 key 名称为 savedText ;页面加载时检查 localStorage 中是否有缓存文本数据,若有则将输入框( id=text )内容设置为相应的文本;当用户点击“发表”按钮( id=post )时,清空输入框( id=text )中的内容,并将 localStorage 内缓存的文本数据移除。
    • 此阶段的页面效果可以查看 effect-1.gif 文件。
  3. 当输入框中没有文字时,将“发表”按钮( id=post )的 disabled 属性值设置为 disabled ;如果输入框中有文字则移除该属性。
    • 注意:当用户点击“发表”按钮和初次进入页面时也会改变输入框的内容,此时也需要对按钮的情况作出判断。
    • 页面最终效果可以查看 effect-2.gif 文件

目标一:防抖函数

function debounce(fn, delay) {
  //return fn; // 这一行是为了确保页面正常运行,可以去掉

  // TODO: 请实现函数防抖的功能
  let timer=null
  return function(){
    clearTimeout(timer)
    timer =setTimeout(fn,delay)
  }
}

目标二: 

document.addEventListener("DOMContentLoaded", function() {
  // TODO: 请在此补充页面加载时缓存检查的代码
 let savedText=localStorage.getItem('savedText')
 if(savedText){
  document.querySelector('#text').value=savedText
 }
 const content =document.querySelector('#text').value
 if(content==''){
  document.querySelector('#post').setAttribute('disabled','disabled')
 }else{
  document.querySelector('#post').removeAttribute('disabled')
 }
});


   // TODO: 请在此补充用户输入时设置缓存和调整按钮状态的代码
    const content =document.querySelector('#text').value
    localStorage.setItem('savadText',content)
    if(content==''){
      document.querySelector('#post').setAttribute('disabled','disabled')
    }else{
      document.querySelector('#post').removeAttribute('disabled')
    }



document.getElementById("post").addEventListener("click", function() {
  const content = document.getElementById("text").value;
  const element = createContent(content);
  document.querySelector(".contents").appendChild(element);
  document.getElementById("prompt").textContent = "";

  // TODO: 请在此补充用户点击“发表”按钮时清空文本框和缓存的代码
  document.querySelector('#text').value=''
  localStorage.clear();
  document.querySelector('#post').setAttribute('disabled','disabled');
})

5. 美食蛋白质揭秘 

目标

找到 index.html 中的 TODO 部分,完成以下目标:

  1. 在不使用任何第三方库的情况下完成数据请求,请求地址必须使用提供的变量 MockURL,数据中 name 表示食物名称,value 表示蛋白质含量,将数据正确渲染到 .protein-container 中,使用 .protein-item 元素渲染数据,元素中显示食物名称和蛋白质含量,正确渲染后的 DOM 如下所示:
<div class="protein-container">
  <div class="protein-item">鸡胸肉 30</div> 
  <div class="protein-item">牛肉 26</div> 
  <!-- 省略代码...... -->
</div>
  1. 在请求完成后,调用 echartsInit 方法渲染图表,参数 data 须是下面的数据结构图标才会正确渲染:
[
  { name: "表头", icon: "none" },
  // 原有数据
  { value: 30, name: "鸡胸肉" },
  // 省略 .......
];

完成后效果如下:

完成效果

 题解

<div class="protein-container" >
            <!-- TODO:待补充代码,渲染获取的数据 -->
            <div class="protein-item" v-for="item in proteinList">{{item.name}} {{item.value}}</div>
        </div>


async function fetchData() {
                    // TODO:待补充代码 
                    const data = await fetch(MockURL).then(response=>response.json())
                    console.log(data);
                    proteinList.value = data
                    let obj = { name:'表头',icon:'none' }
                    const echartsData = Array.from(data)
                    echartsData.unshift(obj)
                    echartsInit(echartsData)
                }
                fetchData()
                return {
                    echartsInit,
                    proteinList,
                };

6. 营业状态切换

 function useToggle(state) {
            // TODO:待补充代码
            // const [state, setState] = useState(initialState);
            // return true
            const toggle = () => {
            setState(!state);
         };
  
       // 返回状态和切换状态函数的数组
           return [state, toggle];
        }

        const app = Vue.createApp({
            setup() {
                const [isWorking, toggleWorking] = useToggle(false) // 使用自定义的useToggle函数创建状态和切换函数
                const workImage = './images/open.jpg' // 营业状态的图片路径
                const restImage = './images/close.jpg' // 打烊状态的图片路径
                return {
                    isWorking,
                    toggleWorking,
                    workImage,
                    restImage
                }
            }
        });

9. 这是一个“浏览器”

目标

完善 js/index.js 文件,找到其中的 TODO 部分,完成代码,达到以下目标:

  1. 补全 js/index.js 中的 toggleTab 函数,实现当点击标签页时,标签页与其内容页变为选中状态(即标签页加上类名 liactive ,内容页加上类名 conactive)。

    上述且后文描述中的标签页是指 .fisrstnav ul 下的每个 li 标签,内容页是指 .tabscon 下的每个 section 标签。

    完成效果如下: 

    图片描述

  2. 完善 js/index.js 中的 editTab 函数,实现当双击标签页文字或者内容页文字时出现输入框,当输入框失焦时,原标签页文字或内容页文字替换为输入框中输入的值。

    上述且后文描述中的标签页文字是指类名为 content 的 span 标签中的文本;内容页文字是指 .tabscon 下的每个 section 标签的文本;输入框是指双击后出现的 input 标签。

    完成效果如下: 

    图片描述

  3. 补全 js/index.js 中的 addTab 函数,实现当点击 .tabadd 时,页面添加新的标签页(即创建一个 li 标签作为子元素插入到 .firstnav ul 节点下)和内容页(即创建一个 section 标签作为子元素插入到 .tabscon 节点下),新标签页及其内容页默认是选中状态。标签页及其内容页内容替换规则:

  • 标签页的内容分别按照序号 “标签页1、标签页2、标签页3......” 依次递增。

  • 内容页的内容分别按照序号 “标签页1的内容、标签页2的内容、标签页3的内容......” 依次递增。

    .firstnav ul 的 DOM 结构为:

    <ul>
       <li>
           <span class="content">标签页1</span>
           <span class="iconfont icon-guanbi">
               <span class="glyphicon glyphicon-remove">
               </span>
           </span>
       </li>
       <li>
           <span class="content">标签页2</span>
           <span class="iconfont icon-guanbi">
               <span class="glyphicon glyphicon-remove">
               </span>
           </span>
       </li>
       <li>
           <span class="content">标签页3</span>
           <span class="iconfont icon-guanbi">
               <span class="glyphicon glyphicon-remove">
               </span>
           </span>
       </li>
    </ul>
    

    .tabscon 的 DOM 结构为:

    <div class="tabscon">
     <section>标签页1的内容</section>
     <section>标签页2的内容</section>
     <section>标签页3的内容</section>
    </div>
    

    完成效果如下: 

    图片描述

  1. 补全 js/index.js 中的 removeTab 函数,实现当点击某个标签页的 .icon-guanbi 时,该标签页及其内容页从页面中删除,所有标签页及其内容页的内容仍以目标 3 中的规则开始重新排,标签页的选中状态也随之改变。标签页状态改变规则:
  • 若删除的标签页是当前选中的标签页,且非最后一个,则该标签页临近的下一个标签页变为选中状态。

  • 若删除的标签页是当前选中的标签页,且为最后一个,则该标签页临近的上一个标签页变为选中状态。

  • 若删除的标签页不是当前选中的标签页,则标签页选中状态不变。

    完成后效果如下:

    图片描述

题解

目标一

  // 1.切换功能
  toggleTab(tab) {
    // TODO: 添加代码,点击标签页,切换到对应标签页的功能
    tab.clearClass();
    this.classList.add('liactive')
    tab.sections[this.index].classList.add('conactive')
    
    // TODO结束
  }

 目标二

  // TODO:实现双击修改内容,当文本框失焦时,把修改的值赋给被双击的对象,并作上已修改的标记
    input.onblur=()=>{
      this.innerText=input.value
    }
    // TODO结束

目标三

addTab(tabObj) {
    tabObj.clearClass();
    let num = tabObj.lis.length;
    let li = `<li class="liactive"><span class="content">标签页${num + 1}</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span></li>`
    let section = `<section class="conactive">标签页${ num + 1 }的内容</section>`
    tabObj.ul.insertAdjacentHTML('beforeend', li);
    tabObj.fsection.insertAdjacentHTML('beforeend', section);
    tabObj.init();
  }

目标四

 removeTab(tabObj, e) {
    e.stopPropagation();
    let index = this.parentNode.index, flag = 0;
    if(tabObj.lis[index].classList.value){
      flag = ((index !== tabObj.lis.length - 1) ? 2 : -1)
    }
    let nextP = tabObj.lis[index + flag],
        nextT = tabObj.sections[index + flag];
    tabObj.lis[tabObj.lis.length - 1].remove();
    tabObj.sections[tabObj.lis.length - 1].remove();
    if(tabObj.lis.length === 1){
      tabObj.init();return;
    }
    nextP ? nextP.className += 'liactive'  : '';
    nextT ? nextT.className += 'conactive' : '';
    tabObj.init();
  }

完整代码

"use strict";
class Tab {
  // 构造方法
  constructor(id) {
    // 获取元素
    this.main = document.querySelector(id);
    this.add = this.main.querySelector(".tabadd");
    this.ul = this.main.querySelector(".fisrstnav ul");
    this.fsection = this.main.querySelector(".tabscon");
    this.init();
  }
  // 初始化
  init() {
    this.updateNode();
    // init初始化操作让相关元素绑定事件
    this.add.onclick = this.addTab.bind(this.add, this);
    for (var i = 0; i < this.lis.length; i++) {
      this.lis[i].index = i;
      this.lis[i].onclick = this.toggleTab.bind(this.lis[i], this);
      this.remove[i].onclick = this.removeTab.bind(this.remove[i], this);
      this.spans[i].ondblclick = this.editTab;
      this.sections[i].ondblclick = this.editTab;
    }
  }
  // 更新所有的li和section
  updateNode() {
    this.lis = this.main.querySelectorAll("li");
    this.remove = this.main.querySelectorAll(".icon-guanbi");
    this.sections = this.main.querySelectorAll("section");
    this.spans = this.main.querySelectorAll(".content");
  }
  // 1.切换功能
  toggleTab(tab) {
    // TODO: 添加代码,点击标签页,切换到对应标签页的功能
    tab.clearClass();
    this.classList.add('liactive')
    tab.sections[this.index].classList.add('conactive')
    
    // TODO结束
  }
  // 2.清空所有标签页及其内容页类名
  clearClass() {
    for (var i = 0; i < this.lis.length; i++) {
      this.lis[i].className = "";
      this.sections[i].className = "";
    }
  }
  addTab(tabObj) {
    tabObj.clearClass();
    let num = tabObj.lis.length;
    let li = `<li class="liactive"><span class="content">标签页${num + 1}</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span></li>`
    let section = `<section class="conactive">标签页${ num + 1 }的内容</section>`
    tabObj.ul.insertAdjacentHTML('beforeend', li);
    tabObj.fsection.insertAdjacentHTML('beforeend', section);
    tabObj.init();
  }
  removeTab(tabObj, e) {
    e.stopPropagation();
    let index = this.parentNode.index, flag = 0;
    if(tabObj.lis[index].classList.value){
      flag = ((index !== tabObj.lis.length - 1) ? 2 : -1)
    }
    let nextP = tabObj.lis[index + flag],
        nextT = tabObj.sections[index + flag];
    tabObj.lis[tabObj.lis.length - 1].remove();
    tabObj.sections[tabObj.lis.length - 1].remove();
    if(tabObj.lis.length === 1){
      tabObj.init();return;
    }
    nextP ? nextP.className += 'liactive'  : '';
    nextT ? nextT.className += 'conactive' : '';
    tabObj.init();
  }
  // 5.修改功能
  editTab() {
    var str = this.innerHTML;
    window.getSelection
      ? window.getSelection().removeAllRanges()
      : document.Selection.empty();
    this.innerHTML = '<input type="text" />';
    var input = this.children[0];
    input.value = str;
    input.select(); //让文本框里的文字处于选定状态
    // TODO:实现双击修改内容,当文本框失焦时,把修改的值赋给被双击的对象,并作上已修改的标记
    input.onblur=()=>{
      this.innerText=input.value
    }
    // TODO结束
  }
}
var tab = new Tab("#tab");

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐