1. 动态的 Tab 栏
/* TODO: 请在此补充代码实现tab栏动态固定 */
/* position:fixed; */
position: sticky;
top: 0;
2. 冰墩墩心情刻度尺
// TODO: 待补充代码
BingDunDun.className='BingDunDun not-satisfied'
range.onchange = (e) => {
let value = Number(e.target.value); // value 进度条的值
// TODO: 待补充代码
console.log(value);
if(value===25){
BingDunDun.className='BingDunDun a-little-unsatisfied'
}else if(value===50){
BingDunDun.className='BingDunDun ordinary'
}else if(value===75){
BingDunDun.className='BingDunDun satisfied'
}else if(value===100){
BingDunDun.className='BingDunDun great'
}else{
BingDunDun.className='BingDunDun not-satisfied'
}
};
3. 迷惑的 this
//事件处理函数
handle() {
// TODO:待补充代码
let inputEl=document.querySelector("input");
inputEl.addEventListener('input',(value)=>{
this.handleInput(value)
})
},
4. 魔法失灵了
//TODO:待修复代码
// let { value }={ ...data }
let { value }=toRefs(data)
function update(val) {
value = val
}
5. 燃烧你的卡路里
//目标一
//html
<el-drawer title="我是标题" v-model="drawer" :with-header="false" size="60%" :direction="direction" >
//js
<const submit = async() => {
// TODO 待添加的代码 功能显示抽屉组件
drawer.value=true
6. 司龄统计
目标
找到 js/index.js
中的,完成其中的 TODO 部分,完成以下目标:
- 找到
groupByAge
函数,groupByAge
接收一个参数,参数为数组对象,age
代表司龄,name
代表人名,返回一个根据司龄进行分组的对象,key
是司龄,value
是一个数组,其中包含了所有当前司龄的人的对象。
- 参数格式示例如下:
[
{ name: "杰克", age: 1 },
{ name: "丽莎", age: 2 },
{ name: "艾娃", age: 5 },
{ name: "约翰", age: 1 },
{ name: "豪尔赫", age: 2 },
]
- 返回值为
object
,格式示例如下:
// 根据司龄(`age`)进行分组,司龄对应司龄人数的数组:
{
1: [{ name: '杰克', age: 1 }, { name: '约翰', age: 1 }], // 司龄为 1 的数组
2: [{ name: '丽莎', age: 2 }, { name: '豪尔赫', age: 2 }], // 司龄为 2 数组
5: [{ name: '艾娃', age: 5 } ]// 司龄为 5 数组
}
- 正确设置 ECharts 图表中的 x 轴和 y 轴数据,x 轴表示司龄,从小到大排序,y 轴表示司龄对应的人数个数。如 1 年司龄的有 4 人,则 y 轴对应的数据为 4。
完成后效果如下:
题解
const groupByAge = (peoples) => {
// TODO:待补充代码,按照年龄进行分组
let ageres=new Object();
for(let i=0;i<peoples.length;i++){
let age=peoples[i].age;
if(ageres[age]){
let arr1=ageres[age];
arr1.push(peoples[i]);
ageres[age]=arr1;
}else{
let arr2=new Array();
arr2.push(peoples[i]);
ageres[age]=arr2;
}
}
return ageres;
};
setup() {
const { updateData } = useECharts();
let xAxisData = Vue.ref([]); // X 轴数据,司龄从小到大排列
let seriesData = Vue.ref([]); // Y 轴数据,司龄对应的人数
const groupedPeople = Vue.ref([]); // table 中显示的数据
Vue.onMounted(async () => {
const data = await (await fetch("./mock/data.json")).json();
groupedPeople.value = groupByAge(data); //把请求回来的数据变成需要的数据格式
// TODO: 设置 Echars X 轴数据 xAxisData 和 Y 轴数据 seriesData
console.log(groupedPeople.value);
let arrX=[];
let arrY=[];
for(key in groupedPeople.value){
arrX.push(key);
arrY.push(groupedPeople.value[key].length)
}
xAxisData.value=arrX;
seriesData.value=arrY
// 更新 echars 数据
updateData(xAxisData.value, seriesData.value);
});
return {
groupedPeople,
};
},
7. 不翼而飞的余额——route
目标
完善 index.html
、js/store.js
和 component/DepositPage.js
中的代码。实现以下效果:
- 找到
index.html
中的 TODO 部分,为项目配置history
模式路由,浏览器中访问/
的时候显示WalletPage
组件,访问/deposit
的时候显示DepositPage
组件。
tips: 目标 1 完成后点击
deposit
按钮或底部的导航的deposit
导航文字,均会跳转到DepositPage
存款页面。
- 找到
DepositPage.js
中的 TODO 部分,在DepositPage
页面中的 (id = deposit-balance
)元素正确显示钱包余额(store
中的balance
)。 - 完善
js/store.js
和component/DepositPage.js
中的 TODO 部分,在DepositPage
页面中,在输入框(input
)输入数字(只考虑正整数),点击 “Deposit” 按钮(button
)后,余额 = 现在的余额 + 输入框中输入的金额,在DepositPage
页面正确显示钱包余额(两个页面的余额相同)。初始余额为 23。
完成后效果如下:
题解
//目标1——路由
<script>
const { createApp } = Vue;
const { createPinia } = Pinia;
const { createRouter,createWebHistory} = VueRouter; // TODO:待补充代码,在此引入路由相关 API
const app = createApp({});
app.use(createPinia());
const router = createRouter({
// TODO:待补充代码,为项目配置 history 模式的路由
history:createWebHistory(),
routes:[
{path:"/",component:WalletPage},
{path:"/deposit",component:DepositPage}
]
})
app.use(router)
// 注册组件
app.mount("#app");
</script>
//目标二:插值语法
<!-- TODO:待补充代码,在 # deposit-balance 中正确显示钱包余额 -->
<span id="deposit-balance">{{store.balance}}</span>
return {
deposit,
store
}
// TODO:待补充代码,完善点击存款按钮事件
function deposit() {
console.log(depositAmount);
store.balance+=depositAmount.value
depositAmount.value=''
}
return {
deposit,
store,
depositAmount
}
8. 个性化推荐
目标
请在 js/index.js
文件中补全代码,最终实现个性化推荐的功能。
首先,在终端运行以下命令启动服务器:
node ./js/index.js
当看到终端输出:server is running in port 8080
,表明服务器启动成功。
并在浏览器中通过 8080 端口预览 index.html
页面,显示如下所示:
在完成勾选后,点击确认,页面会发送 post
请求并跳转到新的页面,你需要根据用户的勾选项,从 data.json
中查询对应的数据,并读取 customized.html
文件的内容,两者结合生成结果页面数据,并返回给前端浏览器:
- 如果用户没有勾选任何标签,直接点击确认,新页面给与提示:
提示信息的 DOM 结构如下:
<div class="unselect">你还未选择任何感兴趣的标签!</div>
- 如果用户勾选了标签,则返回对应的标签的查询信息以及相关推荐,比如用户选择了标签
Javascript
,除了查询tag
为Javascript
的内容,也需要查询Javascript
的相关推荐标签HTML5
,CSS3
的内容(即relevance
字段对应的数据),一并返回。- 注意:不再需要进一步查询相关推荐的相关推荐,即不需要查询
HTML5
的相关推荐标签的内容。 - 多个标签之间的相关标签可能重复,需要对查询内容进行去重,比如选择了标签
Javascript
和CSS3
,最终的去重结果应该是标签Javascript
、CSS3
、HTML5
的内容。
- 注意:不再需要进一步查询相关推荐的相关推荐,即不需要查询
每一条信息的 DOM 结构如下:
<div class="interest">
<div class="tag">标签名</div>
<div>标签内容</div>
</div>
customized.html
文件中已提供基础的样式,请保证你生成的节点带有指定的 class 信息,并填充到 body 中。 在代码更新后,请记得重启服务器!
9. 贪吃蛇
目标
找到 index.js
文件中的 nextStep
函数,完成函数中的 TODO 部分:
- 根据当前蛇的移动方向(
this.direction
)以及蛇身块的大小(this.size
),计算新的蛇头位置,更新蛇身坐标数组 (this.snakeBody
),即可实现蛇的正确移动。蛇的移动和增加蛇的长度代码已提供。
蛇身坐标示例如下:
[{ left: 2, top: 0 }, { left: 1, top: 0 }, { left: 0, top: 0 }]`
蛇的身体是由多个坐标点组成的,每个坐标点包含了 left
和 top
属性,分别表示在游戏界面中的水平和垂直位置,第一个坐标表示当前蛇头的位置。
完成后,效果如下:
规定
- 请勿修改已经提供的代码,以免造成判题无法通过。
- 请严格按照考试步骤操作,切勿修改考试默认提供项目中的文件名称、文件夹路径等。
- 满足题目需求后,保持 Web 服务处于可以正常访问状态,点击「提交检测」系统会自动判分
10. 自定义表单验证器
目标
-
完成
FormInput.js
中的 TODO 部分,当输入框(class= form-input
) 的值变化时,触发事件更新index.html
中组件(form-input
)的v-model
值。(调试 tips:考生可以在点击按钮时通过打印formData
的值进行查看)。 -
完成
js/util.js
中的is_email
函数,参数是邮箱地址,是合法邮箱返回true
,否则返回false
。
合法邮箱包含两个部分:
-
用户名部分:
- 用户名的结尾是
@
符。 @
符之前为至少 1 位字符(数字或字母)。
- 用户名的结尾是
-
域名部分:
- 中间必须是
.
。 .
之前为至少 1 位字符(数字、字母)。.
之后为 2 到 4 位字母。
- 中间必须是
合法邮箱示例: a@b.cn
、1A@88.com
不合邮箱示例: 1@1.c
、1@
、33.cn
、Ab.cn@
- 完成
components/FormValidator.js
中通用表单验证函数validateForm
中的 TODO 部分。如果表单验证通过,则Promise
为resolve(true)
,否则为resolve(false)
(此部分代码已提供)。index.html
中定义的formRules
对象对应字段的表单值验证失败时,使用validateForm
函数中提供的errors
对象,在对应字段中存储错误信息。若某个字段对应的错误信息为多个时,将按照验证规则数组的顺序优先显示,即只显示第一个错误信息。函数使用的数据通过props.rules
(字段名和对应的验证规则) 和props.formData
(表单数据的键值对) 进行获取。
例: email
为空显示了错误信息 邮箱不能为空
,则不再显示 邮箱不符合规则或者长度不符
这个错误信息。
errors
数据结构示例:
{
phone: "请输入密码", // 对应字段为 phone 的错误信息
email: "邮箱不能为空" // 对应字段为 email 的错误信息
}
表单每个字段对应的验证规则为一个数组,验证规则示例的配置如下:
// 定义表单验证规则
const formRules = {
phone: [{ validator: validatePass }], // 针对 phone 字段的验证规则
email: [
{ required: true, message: "邮箱不能为空" }, // 邮箱字段必填规则
{ type: "email", min: 8, max: 20, message: "类型必须为邮箱" }, // 邮箱格式规则
],
};
formRules
对应字段说明如下:
注意:自定义验证函数 validator
不会和其他字段同时出现,其他字段均可同时出现。
参数名(Parameter) | 类型(Type) | 描述(Description) |
---|---|---|
validator | Function | 表单自定义验证函数,接受三个参数,分别为 rule 表单验证规则数组,value 验证表单的值,callback 回调函数。如果验证成功,callback 函数不做任何处理;如果验证失败,callback 函数接收参数 error 并将其中的文字存储在 errors 对象中,且参数 error 的值为其调用者传递过来的 new Error('这里是错误信息') ,其中错误信息是验证失败的具体描述。callback 函数的调用逻辑 index.html 中已经提供,考生只需实现字段验证及 errors 错误信息存储的逻辑即可。 |
required | Boolean | 表示表单字段是否为必填项。 |
type | String | 字段类型,通过 FormValidator 中已提供的 validateByType 函数进行验证,该函数接收的参数为 type ,类型正确则返回 true ,否则返回 false |
min | Number | 指定表单输入的最小长度。 |
max | Number | 指定表单输入的最大长度。 |
message | String | 验证失败时的错误信息 |
完成后示例效果如下: