题目
题目描述
- 设计一个TODO List,页面结构如下图所示,要求:
-
使用HTML与CSS完成界面开发
-
实现添加功能:输入框中可输入任意字符,按回车后将输入字符串添加到下方列表的最后,并清空输入框
-
实现删除功能:点击列表项后面的“X”号,可以删除该项
-
实现模糊匹配:在输入框中输入字符后,将当前输入字符串与已添加的列表项进行模糊匹配,将匹配到的结果显示在输入框下方。如匹配不到任何列表项,列表显示空
注:以上代码实现需要能在浏览器中正常显示与执行。
代码
<!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>
- 主要问题:
- 添加和删除本质上是比较简单的,原生DOM也可以实现
- 主要难点是搜索匹配,这让我直接CDN引入Vue外挂,颜色高亮搜索要和codemirror一样每个字符单加span
- CDN下可以用compositon-API,但是更多特性需要引入其他包,为了方便可以只用options-API
- 核心事件-回车:键盘输入回车通过@keydown.enter事件监听,或@keydown=“f”,在函数参数e中keyCode属性判断
- 核心事件-输入:通过@input事件
- 一些vue常见问题,v-for指定key高效更新VNODE,v-if和v-for不要同一个元素上使用
- 没完成的任务:模糊匹配,因为不确定有多模糊,所以暂时按精准匹配做了,可以去121行改匹配的逻辑
- CDN速记:next
- CDN:https://unpkg.com/vue@next
- 语法:
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
data() {
return {
hello: 'world",
};
},
}).mount('#app');
</script>
- CDN速记:dist
- CDN:https://unpkg.com/vue@3.0.7/dist/vue.esm-browser.js
- 语法:
<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>
测试
-
添加
-
匹配
-
删除