团队开发中为了解决变量相互覆盖的问题,会将相关的功能的涉及到变量收编到一个对象内。但使用对象收编变量后需要注意
this
合理使用。
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css
│ └── style.css
├── index.html
└── js
└── index.js
其中:
index.html
是主页面。css
是存放项目样式的文件夹。js/index.js
是需要补充代码的 js 文件。注意:打开环境后发现缺少项目代码,请复制下述命令至命令行进行下载。
cd /home/project
file="this" && wget "https://labfile.oss.aliyuncs.com/courses/19791/${file}.zip" && unzip "${file}.zip" && rm "${file}.zip"
选中 index.html
右键启动 Web Server 服务(Open with Live Server),让项目运行起来。
接着,打开环境右侧的【Web 服务】,就可以在浏览器中看到如下效果:
完善
js/index.js
中的handle
函数中的 TODO 部分,实现以下功能:
this.inputEl
)绑定 input
事件,当输入框的值发生变化时,调用已经提供的 handleInput
方法进行搜索处理,注意 handleInput
方法调用时的 this
指向应为 search
对象本身。最终完成的效果如下:
// index.js
const data = [
{ id: 1, content: "明日方舟" },
{ id: 2, content: "明朝" },
{ id: 3, content: "明天会更好" },
{ id: 4, content: "明星" },
{ id: 4, content: "m" },
{ id: 5, content: "mi" },
{ id: 6, content: "min" },
{ id: 7, content: "ming" },
];
const search = {
inputEl: null,
listEl: null,
data: [],
init(options) {
this.initData(options.el);
this.handle();
},
initData(el) {
//获取页面上的输入框
this.inputEl = el.querySelector("input");
//获取页面上的显示项的ul标签
this.listEl = el.querySelector(".search-list");
},
//事件处理函数
handle() {
// 为输入框绑定 input 事件
this.inputEl.addEventListener('input', this.handleInput.bind(this));
},
// 搜索处理函数
handleInput(e) {
const value = e.target.value;
// 使用定时器模拟 ajax 发送请求,data 接收数据
setTimeout(() => {
this.data = !!value
? data.filter((val) => val.content.indexOf(value) !== -1)
: [];
// 渲染搜索结果到页面上的列表
this.render();
});
},
render() {
// 根据得到的数组转化为 li 标签,并插入到 .search-list 元素(ul标签)内
const template = this.data.reduce(
(prev, next) => prev + `<li>${next.content}</li>`,
""
);
this.listEl.innerHTML = template;
},
};
search.init({
el: document.getElementById("app"),
});
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>迷惑的this</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<div id="app">
<div class="search">
<div class="search-inp">
<input
id="input-search"
type="text"
placeholder="请输入需要查找的内容"
maxlength="60"
/>
</div>
<div class="search-btn">搜索</div>
</div>
<ul class="search-list"></ul>
</div>
<script src="./js/index.js"></script>
</body>
</html>
<!DOCTYPE html>
:声明文档类型为 HTML5。<meta charset="UTF-8" />
:设置字符编码为 UTF - 8,确保页面能正确显示各种字符。<meta http-equiv="X-UA-Compatible" content="IE=edge" />
:让页面在 Internet Explorer 中以最新的渲染模式显示。<meta name="viewport" content="width=device-width, initial-scale=1.0" />
:设置页面在不同设备上的显示比例和宽度自适应。<title>迷惑的this</title>
为页面设置标题。<link rel="stylesheet" href="./css/style.css">
引入外部 CSS 文件,用于美化页面。<div id="app">
:作为整个应用的容器。<div class="search">
:包含搜索框和搜索按钮的容器。<input>
:输入框,用于用户输入要搜索的内容,placeholder
属性提供提示信息,maxlength
属性限制输入的最大长度。<div class="search-btn">
:搜索按钮。<ul class="search-list"></ul>
:无序列表,用于显示搜索结果。<script src="./js/index.js"></script>
引入外部 JavaScript 文件,实现搜索功能。* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
body {
background-color: #f0f3f5;
}
#app {
margin: 10px auto;
width: 80%;
}
.search {
display: flex;
justify-content: flex-start;
align-items: flex-start;
}
.search-inp {
width: 70%;
height: 34px;
}
input {
width: 100%;
height: 100%;
padding-left: 10px;
border: none;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
box-shadow: 0px 1px 2px #ccc;
outline: none;
}
.search-btn {
width: 37px;
height: 34px;
line-height: 34px;
text-align: center;
background-color: #929ba2;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
outline: none;
color: #fff;
}
.search-list {
width: 70%;
background-color: #fff;
margin-top: 10px;
}
* { margin: 0; padding: 0; }
:清除所有元素的默认内外边距。li { list - style: none; }
:去除列表项的默认样式。body { background - color: #f0f3f5; }
设置页面背景颜色。#app
设置容器的外边距和宽度,使其居中显示。.search
使用 Flexbox 布局,让搜索框和按钮水平排列。.search - inp
设置搜索框容器的宽度和高度。input
设置输入框的样式,包括宽度、高度、内边距、边框圆角和阴影等。.search - btn
设置搜索按钮的样式,包括宽度、高度、背景颜色、边框圆角和文字颜色等。.search - list
设置搜索结果列表的宽度、背景颜色和上边距。const data = [
{ id: 1, content: "明日方舟" },
{ id: 2, content: "明朝" },
{ id: 3, content: "明天会更好" },
{ id: 4, content: "明星" },
{ id: 4, content: "m" },
{ id: 5, content: "mi" },
{ id: 6, content: "min" },
{ id: 7, content: "ming" },
];
const search = {
inputEl: null,
listEl: null,
data: [],
init(options) {
this.initData(options.el);
this.handle();
},
initData(el) {
//获取页面上的输入框
this.inputEl = el.querySelector("input");
//获取页面上的显示项的ul标签
this.listEl = el.querySelector(".search-list");
},
//事件处理函数
handle() {
// 为输入框绑定 input 事件
this.inputEl.addEventListener('input', this.handleInput.bind(this));
},
// 搜索处理函数
handleInput(e) {
const value = e.target.value;
// 使用定时器模拟 ajax 发送请求,data 接收数据
setTimeout(() => {
this.data = !!value
? data.filter((val) => val.content.indexOf(value) !== -1)
: [];
// 渲染搜索结果到页面上的列表
this.render();
});
},
render() {
// 根据得到的数组转化为 li 标签,并插入到 .search-list 元素(ul标签)内
const template = this.data.reduce(
(prev, next) => prev + `<li>${next.content}</li>`,
""
);
this.listEl.innerHTML = template;
},
};
search.init({
el: document.getElementById("app"),
});
data
数组包含了用于搜索的原始数据。search
对象包含了搜索功能的相关方法和属性。 init
方法:初始化搜索功能,调用 initData
方法获取输入框和列表元素,调用 handle
方法绑定事件。initData
方法:通过 querySelector
方法获取页面上的输入框和搜索结果列表元素。handle
方法:为输入框绑定 input
事件,当输入框内容变化时触发 handleInput
方法。handleInput
方法:获取输入框的值,使用 setTimeout
模拟异步请求,过滤出包含输入值的数据,并调用 render
方法渲染结果。render
方法:将过滤后的数据转换为 HTML 字符串,并插入到搜索结果列表中。四、修复 BUG 的工作流程▶️
this
的指向会根据函数的调用方式而变化。在事件处理函数中,this
通常指向触发事件的元素,而不是对象本身。为了确保 handleInput
方法中的 this
指向 search
对象,我们使用了 bind
方法。
handle
方法中,使用 addEventListener
为输入框绑定 input
事件。bind
方法:this.inputEl.addEventListener('input', this.handleInput.bind(this));
,bind
方法会创建一个新的函数,在调用时将 this
绑定到指定的对象(这里是 search
对象)。input
事件,调用 handleInput
方法。this
指向正确:由于使用了 bind
方法,handleInput
方法中的 this
指向 search
对象,从而可以正确访问 search
对象的属性和方法,如 this.data
和 this.render()
。