『前端刷题』字节18校招前端二批 - 第4题 - TODO List

本文档介绍了一个使用Vue实现的TODO List,包括HTML和CSS的界面设计,以及添加、删除功能的实现。重点在于模糊匹配功能,要求输入框中的字符与列表项进行模糊匹配,并在输入框下方显示匹配结果。文章提供了CDN引入Vue的链接及代码实现,但目前的模糊匹配仅实现了精准匹配,可进一步优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

题目

题目描述

  • 设计一个TODO List,页面结构如下图所示,要求:
  1. 使用HTML与CSS完成界面开发

  2. 实现添加功能:输入框中可输入任意字符,按回车后将输入字符串添加到下方列表的最后,并清空输入框

  3. 实现删除功能:点击列表项后面的“X”号,可以删除该项

  4. 实现模糊匹配:在输入框中输入字符后,将当前输入字符串与已添加的列表项进行模糊匹配,将匹配到的结果显示在输入框下方。如匹配不到任何列表项,列表显示空

注:以上代码实现需要能在浏览器中正常显示与执行。

代码

<!DOCTYPE html>
<html lang="ch">
  <head>
    <title>exam</title>
    <style type="text/css">
      .toDoList {
        position: relative;
        width: 50vw;
        min-height: 50vh;
        margin: 50px 0 0 50px;
        padding-bottom: 50px;
        background-color: #eeeeee;
        display: flex;
        flex-flow: column nowrap;
      }
      .toDoList > section {
        display: flex;
        justify-content: center;
      }
      .titleText {
        text-align: center;
        font-size: 4em;
        font-weight: 100;
        color:lightcoral;
      }
      .inputText, .extendText {
        width: 50%;
        height: 40px;
        outline: none;
        font-size: 1.5em;
        font-weight: 100;
        padding: 0 0 0 20px;
        border: 1px solid #aaaaaa;
      }
      .extendText {
        position: relative;
        background-color: white;
        border-top: none;
      }
      .extend {
        display: flex;
        flex-flow: column wrap;
        align-items: center;
        justify-content: center;
      }
      .deleteButton {
        position: absolute;
        right: 10px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <article class="toDoList">
        <section class="title">
          <span class="titleText">todos</span>
        </section>
        <section class="input">
          <input
            type="text"
            class="inputText"
            spellcheck="false"
            v-model="search"
            @keydown.enter="addItem"
            @input="searchMatch"
          >
        </section>
        <section class="extend">
          <div
            class="extendText"
            v-for="(listItem, idx) in list"
            :key="idx"
            v-show="listItem.show"
          >
            <span
              v-for="(valueItem, idx) in listItem.content"
              :key="idx"
              :style="{ 'color': valueItem.check ? 'red' : 'black' }"
            >
              {{ valueItem.value }}
            </span>
            <span
              class="deleteButton"
              @click="deleteLine(index)"
            >
              x
            </span>
          </div>
        </section>
      </article>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
      Vue.createApp({
        data() {
          return {
            list: [], // 已有搜索数据list
            search: '', // 当前搜索值双绑
          };
        },
        methods: {
          addItem(e) { // 添加新行
            this.list.push({
              show: true, // 控制是否展示(搜索使用)
              value: this.search, // 原值
              content: this.search.split('').map((value) => ({ // 分字符渲染
                value, // 值
                check: false, // 是否匹配
              })), // 返回单对象要加括号
            });
            this.search = ''; // 清空搜索串
            this.searchMatch(); // 重置
          },
          deleteLine(index) { // 删除已有行
            this.list.splice(index, 1);
          },
          searchMatch() {
            this.list.forEach((val, idx, arr) => {
              const idxLeft = val.value.indexOf(this.search); // 精准匹配:左索引
              if (idxLeft < 0) {
                arr[idx].show = false; // 通过第三个参数修改原值
              } else {
                const idxRight = idxLeft + this.search.length; // 右索引 = 左索引 + 长度
                for (let i = 0; i < val.value.length; i += 1) { // 在这里翻了个错误,用搜索串长度判断了
                  if (idxLeft <= i && i < idxRight) { // 范围判断
                    arr[idx].content[i].check = true;
                  } else {
                    arr[idx].content[i].check = false; // 重置
                  }
                }
                arr[idx].show = true; // 重置
              }
            })
          },
        },
      }).mount("#app");
    </script>
  </body>
</html>

  • 主要问题:
  1. 添加和删除本质上是比较简单的,原生DOM也可以实现
  2. 主要难点是搜索匹配,这让我直接CDN引入Vue外挂,颜色高亮搜索要和codemirror一样每个字符单加span
  3. CDN下可以用compositon-API,但是更多特性需要引入其他包,为了方便可以只用options-API
  4. 核心事件-回车:键盘输入回车通过@keydown.enter事件监听,或@keydown=“f”,在函数参数e中keyCode属性判断
  5. 核心事件-输入:通过@input事件
  6. 一些vue常见问题,v-for指定key高效更新VNODE,v-if和v-for不要同一个元素上使用
  7. 没完成的任务:模糊匹配,因为不确定有多模糊,所以暂时按精准匹配做了,可以去121行改匹配的逻辑
  • CDN速记:next
  1. CDN:https://unpkg.com/vue@next
  2. 语法:
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({ 
  data() {
    return {
      hello: 'world",
    };
  },
}).mount('#app');
</script>
  • CDN速记:dist
  1. CDN:https://unpkg.com/vue@3.0.7/dist/vue.esm-browser.js
  2. 语法:
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3.0.7/dist/vue.esm-browser.js';
// reactive, ref, watch, computed, defineComponent, onMounted 等等 按需引入

createApp({
  setup() {
  	return {
  		hello: 'world',
  	};
  },
}).mount('#app');
</script>

测试

  • 添加
    在这里插入图片描述

  • 匹配
    在这里插入图片描述

  • 删除
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大熊软糖M

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值