如何使用JavaScript实现某个功能或解决某个问题? | 青训营

如何使用JavaScript实现某个功能或解决某个问题?

JavaScript 是一种非常灵活和强大的编程语言,它可以用来实现各种功能或解决各种问题。

例如,你可以用 JavaScript 来:

  • 创建动态的网页效果,如幻灯片、下拉菜单、弹窗等。
  • 验证用户输入的表单数据,如邮箱、密码、手机号等。
  • 检测用户的浏览器类型和版本,以便为不同的浏览器提供最佳的用户体验。
  • 存储和读取用户的偏好设置,如主题、语言、字体大小等。
  • 与服务器端进行数据交互,如发送请求、接收响应、处理 JSON 数据等。
  • 利用 HTML5 的新特性,如 CanvasAudioVideoGeolocation 等,创建富媒体和交互式的应用。
  • 编写自定义的函数和对象,以实现更复杂和高级的逻辑和算法。

JavaScript如此强大,在编写程序的时候遇到困难如何解决,用一个TodoList案例来演示.。

TodoList案例:

案例最终实现效果如下图:

要求:

  • input框内输入要添加的事项,按回车后能够在列表中添加一个事项。
  • 每个事项的状态为已完成状态后,底部的复选框会自动勾选
  • 点击底部的复选框能够把列表中的所有事项都设为已完成状态或者是未完成状态
  • 点击底部的"清除已完成事项按钮"能够清除列表中所有的已完成事项
  • 底部的已完成事项数和全部的事项数能够跟随用户的操作及时改变

弄清楚要实现那些功能后开始按照以下步骤编写代码。

实现静态网页

这一步先不考虑js的交互效果,先把静态的网页写出来,然后再逐步给页面添加交互效果,所以,很容易写出以下代码:

html 复制代码
<div class="todolist">
    <div class="header">
        <input
               type="text"
               class="something"
               placeholder="请输入你的任务事项,按回车确定"
        />
    </div>
    
    <div class="content">
        <div class="item">
            <input type="checkbox" class="state" />
            <label class="title">Hello world!</label>
        </div>
        <div class="item">
            <input type="checkbox" class="state" />
            <label class="title">hello world!</label>
        </div>
        <div class="item">
            <input type="checkbox" class="state" />
            <label class="title">hello world!</label>
        </div>
    </div>
    
    <div class="footer">
        <input type="checkbox" class="select-all" />
        <span class="sum">已完成 0/全部 3</span>
        <button class="clear">清除已完成事项</button>
    </div>
</div>
css 复制代码
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

.todolist {
  width: 600px;
  margin: 0 auto;
  border: 1px solid gray;
  padding: 5px;
  border-radius: 5px;
}

.todolist .header .something {
  width: 600px;
  height: 30px;
  margin-bottom: 10px;
  border: 1px solid gray;
  box-sizing: border-box;
}

.todolist .content .item {
  width: 600px;
  height: 40px;
  line-height: 40px;
  border: 1px solid gray;
  border-radius: 5px;
  box-sizing: border-box;
}
.todolist .content .item:hover {
  background-color: rgba(128, 128, 128, 0.144);
}

.todolist .footer {
  width: 600px;
  height: 50px;
  line-height: 50px;
  position: relative;
}

.todolist .footer .clear {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translate(0, -50%);
  font-size: 15px;
  background-color: rgb(226, 92, 70);
  color: white;
  border: 1px solid red;
  border-radius: 3px;
  padding: 5px;
  overflow: hidden;
  cursor: pointer;
}

这样就实现了静态网页的效果,当然,展示一个时间列表也可以写成一个<ul>列表展示,实现方法有很多,不必拘泥于一种。

除此之外,我们还要为这个案例添加交互效果,这就要用到我们强大的JavaScript了,我们依次实现我们一开始分析出的功能模块。

添加交互效果

在写JavaScript代码之前,我们要知道在一个大型项目中,同一个功能可能在很多地方都需要用到,并且在该功能的基础上我们还要进行改造或扩展,所以最好我们把所有的功能封装起来,用类来表示。

javascript 复制代码
class TodoList {
  constructor(cName) {
    this.todolist = document.querySelector(cName);
  }
  registerPlugins(...plugins) {
    plugins.forEach((plugin) => plugin(this));
  }
    /* ... */
}

因为这个类是针对于TodoList这个DOM元素的类,类里面的所有操作都是对TodoList这个DOM元素的操作,所以毫无疑问,我们必须要首先拿到这个元素,通过以下代码创建实例。

js 复制代码
const todolist = new TodoList('todolist')

为了方便改造或扩展,我们把所有功能写成插件,通过依赖注入的方式添加交互功能,以后我们可通过如下代码添加功能。

js 复制代码
todolist.registerPlugins(PluginsName1, PluginsName2, ...);

功能一:添加事件

很明显,我们要添加事件就要给顶部的input框绑定事件,按回车后触发事件的回调函数,在回调函数中往列表中添加一个展示事件的DOM元素。

js 复制代码
this.something = this.todolist.querySelector('.header .something');  

this.something.addEventListener("keypress", (evt) => {
  if (evt.keyCode === 13) {
        this.addSomething(evt.target.value);
      }
});

addSomething(str) {
    console.log(str);
    /* ... */
}

以上代码运行后,在网页中我们在input中输入事项后按回车我们能够在控制台看到我们输入的内容,说明目前我们的代码都是ok的,接下来只需要实现addSomething函数就好了。

addSomething函数中,我们要完成元素的创建和添加,按照正常的思路我们要创建元素,为元素设置属性,过程太过繁琐,所以我想到了把HTML文本字符串转换成DOM元素的思路,用DOMParser这个API实现。

js 复制代码
function addsomething(str) {
    this.content = this.todolist.querySelector(".content");
    const temp = `
        <div class="item">
          <input type="checkbox" class="state" />
          <label class="title">${str}</label>
        </div>
      `.trim();
    const node = new DOMParser().parseFromString(temp, "text/html").body
      .childNodes[0];
    const first = this.content.firstChild;
    this.content.insertBefore(node, first);
    this.something.value = "";
}

遇到的问题:

一开始,我也是通过创建元素,为元素设置属性,最后插入元素来实现这块功能的,明显感觉到十分的繁琐,但是我知道反引号可以拼接HTML文本字符串,就有了将HTML文本字符串直接转换成DOM元素的想法,于是开始通过百度,掘金等平台搜索,知道了DOMParser这个API可以实现我的想法,后来在MDN官网查找这个API,大概学会了这个API,可是刚开始用,看别人的实例代码,我写了如下代码:

js 复制代码
const node = new DOMParser().parseFromString(temp, "text/xml");

我把node插入结果却报错了,然后我用console.dir(node)方法输出看了一下,发现有一个documentElement属性能够得到我想要的元素,于是我就把node.documentElement插入网页,没有报错,元素也插入了,可是样式却丢失了,这让我很疑惑。

输出console.log(node.documentElement):

(这个问题暂且搁置,以后再补)

最后也是看MDN文档,试了text/html,通过console.dir()方法,写出了现在的正确写法。

功能二:事件完成

为事件设置已完成状态,点击对应的复选框就可以实现,但关键是我们要统计到目前已经完成的事件数,为最后统计一共完成的事件数做铺垫,我的想法就是为每一个复选框绑定一个点击事件,每次点击统计一次目前已经完成事件的数量,最后与总的事件数作比较,如果相等就把footer里的全选框勾选。

js 复制代码
function isGetItem(todolist) {
  const btn = todolist.content.querySelectorAll(".item .state");
  const getAll = todolist.footer.querySelector(".select-all");
  btn.forEach((item) => {
    item.addEventListener("click", (e) => {
      this.count = 0;
      btn.forEach((x) => {
        if (x.checked) {
          this.count++;
        }
      });
      if (this.count === btn.length) {
        getAll.checked = true;
      } else {
        getAll.checked = false;
      }
	
      /*  自定义事件,与最后的功能(footer 统计)有关
      const detail = { count: this.count };
      const event = new CustomEvent("getItem", { bubbles: true, detail });
      todolist.content.dispatchEvent(event);
      */
    });
  });
}

功能三:全选功能

这点没什么难度,为全选按钮绑定点击事件,然后遍历每个事件的复选框,改变状态。

js 复制代码
function isGetAll(todolist) {
  const getAll = todolist.footer.querySelector(".select-all");
  getAll.addEventListener("click", (e) => {
    const getAllState = getAll.checked;
    todolist.content.querySelectorAll(".item .state").forEach((item) => {
      item.checked = getAllState;
    });
    if (getAllState)
      count = todolist.content.querySelectorAll(".item .state").length;
    else count = 0;
    /* 以下代码与本功能无关
    const detail = { count: count };
    const event = new CustomEvent("getall", { bubbles: true, detail });
    todolist.footer.dispatchEvent(event);
    */
  });
}

功能四:清除事件

js 复制代码
function clearTodo(todolist) {
  const clearBtn = todolist.footer.querySelector(".clear");
  clearBtn.addEventListener("click", (e) => {
    const items = todolist.content.querySelectorAll(".item");
    items.forEach((item) => {
      const state = item.querySelector(".state");
      if (state.checked) todolist.content.removeChild(item);
    });
    this.count = 0;
    /* 与本功能无关
    const detail = {
      count: this.count,
      number: todolist.content.querySelectorAll(".item").length,
    };
    const event = new CustomEvent("clear", { bubbles: true, detail });
    todolist.footer.dispatchEvent(event);
    */
  });
}

这个功能也十分简单,值得注意的一点就是,事件信息的获取实际,一定是要在点击以后重新获取一次,如果获取数据放在点击之前,我们的操作都是对旧数据的操作,在这之前,我们很可能又添加了数据。

功能五:事件统计

统计已完成的事件数和全部的事件数,这个功能牵扯了很多的功能,当初我实现时也是有点乱的,我当时对自定义事件的API是有点陌生的,当时也是没思路,就去重新看了月影老师的js课,看到了js自定义事件,我发现它能实现参数的传递,于是就去看了MDN文档,用自定义事件实现了这个功能。

去除相关功能中的自定义事件的定义,在构造函数中添加如下代码:

js 复制代码
this.header = this.todolist.querySelector(".header");
this.content = this.todolist.querySelector(".content");
this.footer = this.todolist.querySelector(".footer");

this.footer.addEventListener("addTodo", (evt) => {
    this.number = evt.detail.number;
    this.footer.querySelector(".sum .sum2").innerHTML = this.number;
});

this.footer.addEventListener("getall", (evt) => {
    this.count = evt.detail.count;
    this.footer.querySelector(".sum .sum1").innerHTML = this.count;
});

this.footer.addEventListener("clear", (evt) => {
    this.count = evt.detail.count;
    this.number = evt.detail.number;
    this.footer.querySelector(".sum .sum1").innerHTML = this.count;
    this.footer.querySelector(".sum .sum2").innerHTML = this.number;
});

this.content.addEventListener("getItem", (evt) => {
    this.count = evt.detail.count;
    this.footer.querySelector(".sum .sum1").innerHTML = this.count;
});

(以上代码,格式几乎一样,可以封装成一个函数)

总结

通过以上案例,简单总结一下我们该如何使用JavaScript实现某个功能或解决某个问题?

使用 JavaScript 实现某个功能或解决某个问题的方法,可能因为功能或问题的不同而有所差异,但一般来说,我们可以遵循以下几个步骤:

  1. 分析功能或问题的需求,确定要实现或解决的目标和条件,以及可能涉及到的数据和逻辑。
  2. 设计功能或问题的解决方案,选择合适的数据结构和算法,以及需要使用的 JavaScript 语法和特性。
  3. 编写功能或问题的代码,遵循 JavaScript 的编码规范和风格,注重代码的可读性和可维护性。
  4. 测试功能或问题的代码,使用合适的工具和方法,检查代码是否能够正确地运行,并符合预期的结果和效果。
  5. 优化功能或问题的代码,根据测试的反馈,修改和改进代码中存在的错误或不足,提高代码的性能和质量。

以上就是使用 JavaScript 实现某个功能或解决某个问题的一般方法。当然,这些步骤并不是固定不变的,你可以根据具体的情况进行调整和灵活运用,我们要实现某个功能,首先要先确定实现思路,然后再开始写代码,先不急着把完整的功能实现,可以先写一部分,然后执行console.log()函数查看变量或者结果来判断这个思路是否可行,通过console.dir()查看某个对象身上的属性个方法,看有没有想要的结果,在写的过程中,自己有不一样的思路就大胆去写,遇到错误就去搜索,或者去MDN上学习。

相关推荐
CallBack8 个月前
Typora+PicGo+阿里云OSS搭建个人图床,纵享丝滑!
前端·青训营笔记
Taonce1 年前
站在Android开发者的角度认识MQTT - 源码篇
android·青训营笔记
AB_IN1 年前
打开抖音会发生什么 | 青训营
青训营笔记
monster1231 年前
结营感受(go) | 青训营
青训营笔记
翼同学1 年前
实践记录:使用Bcrypt进行密码安全性保护和验证 | 青训营
青训营笔记
hu1hu_1 年前
Git 的正确使用姿势与最佳实践(1) | 青训营
青训营笔记
星曈1 年前
详解前端框架中的设计模式 | 青训营
青训营笔记
tuxiaobei1 年前
文件上传漏洞 Upload-lab 实践(中)| 青训营
青训营笔记
yibao1 年前
高质量编程与性能调优实战 | 青训营
青训营笔记
小金先生SG1 年前
阿里云对象存储OSS使用| 青训营
青训营笔记