一、题1
1.目标
在 JavaScript 和 CSS 中补充代码,使用React或者Vue,按照优先级,实现倒计时抢券功能。
共计3个关键需求点:
功能1:按钮自动倒计时(此功能重要占比60%)进入页面时,卡片中的按钮开始自动 10s 倒计时
倒计时过程中,按钮显示剩余时间(文案为:10s、9s、8s、…、1s)
倒计时结束后,按钮文案变为「抢购」
功能2:抢购功能模拟(此功能重要占比20%)点击抢购按钮时,调用异步模拟请求方法,请求完成后按钮文字变为「已抢购」
异步请求模拟方法需自行实现,延迟 1s 后返回成功即可
功能3:还原券css样式(此功能重要占比20%)副标题最多支持2行,多余2行省略号表示
2.Vue实现
<template>
<div class="box">
<div class="SnapUp">
<ul>
<div class="card">
<div class="title-group">
<h2 class="title">{{ title }}</h2>
<p class="subtitle">{{ formattedSubtitle }}</p>
</div>
<div class="button-group">
<!-- <button v-if="countdown > 0" @click="handleButtonClick">
{{ countdown }}s
</button> -->
<button :disabled="countdown > 0" @click="handleButtonClick">
{{ buttonText }}
</button>
</div>
</div>
</ul>
</div>
</div>
</template>
<script>
//引入状态映射函数
// import { mapActions, mapGetters, mapState } from 'vuex';
export default {
name: 'SnapUp',
data() {
return {
countdown: 10,
title: "杭州市通用5元券",
subtitle: "杭味面我的我读入你都三的那位我怕扽我的皮物品的看热闹使得从从而形成",
buttonText: "抢购"
};
},
mounted() {
this.startCountdown();
},
computed: {
formattedSubtitle() {
if (this.subtitle.length <= 16) {
return this.subtitle;
}
return this.subtitle.substring(0, 16) + "...";
}
},
methods: {
startCountdown() {
this.buttonText = `${this.countdown}s`;
const timer = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
this.buttonText = `${this.countdown}s`;
} else {
clearInterval(timer);
this.buttonText = "抢购";
}
}, 1000);
},
handleButtonClick() {
if (this.buttonText === "抢购") {
// 模拟异步请求
setTimeout(() => {
this.buttonText = "已抢购";
}, 1000);
}
}
}
};
</script>
<style>
.card {
background-color: #fff0f1;
height: 136px;
width: 430px;
border-radius: 12px;
margin-left: 30px;
margin-right: 24px;
display: flex;
align-items: center;
padding: 20px;
}
.card .title-group {
display: flex;
flex-direction: column;
margin-right: 20px;
}
.card .title-group h2 {
font-size: 24px;
font-weight: bold;
margin: 0;
}
.card .title-group p {
font-size: 22px;
font-weight: normal;
margin: 0;
}
.card .button-group {
display: flex;
align-items: center;
}
.card .button-group button {
background-color: #f00;
border: none;
color: #fff;
font-size: 20px;
font-weight: bold;
width: 108px;
height: 45px;
border-radius: 8px;
margin-left: 20px;
}
</style>
二、题2
目标
实现一个 query 方法,实现对数据的链式查询和处理
要求
query 传入参数为原始数据(数组格式,每个元素都是对象)
通过进行链式调用对数据执行操作,支持的方法有where(predicate): 根据参数的条件进行筛选,参数与 [].filter 的参数类似
orderBy(key, desc): 根据 key 的值进行排列,默认升序排列,当第二个参数为 true 时降序排列
groupBy(key): 根据 key 的值对数据元素进行分组,合并为二维数组
execute(): 执行所有处理并返回最终结果
执行 execute 方法时才真正执行操作并返回结果
请结合下面示例理解需求
示例
const data = [
{ name: 'foo', age: 16, city: 'shanghai' },
{ name: 'bar', age: 24, city: 'hangzhou' },
{ name: 'fiz', age: 22, city: 'shanghai' },
{ name: 'baz', age: 19, city: 'hangzhou' }
];
query(data)
.where(item => item.age > 18)
.orderBy('age')
.groupBy('city')
.execute();
// 结果返回
[
[
{ name: 'baz', age: 19, city: 'hangzhou' },
{ name: 'bar', age: 24, city: 'hangzhou' },
],
[
{ name: 'fiz', age: 22, city: 'shanghai' },
]
]
2.JS实现
function query(data) {
let results = [...data];
let operations = [];
const where = (predicate) => {
operations.push({
type: 'where',
predicate
});
return queryFn;
};
const orderBy = (key, desc = false) => {
operations.push({
type: 'orderBy',
key,
desc
});
return queryFn;
};
const groupBy = (key) => {
operations.push({
type: 'groupBy',
key
});
return queryFn;
};
const execute = () => {
operations.forEach(operation => {
switch (operation.type) {
case 'where':
results = results.filter(operation.predicate);
break;
case 'orderBy':
results.sort((a, b) => {
const valueA = a[operation.key];
const valueB = b[operation.key];
return operation.desc ? valueB - valueA : valueA - valueB;
});
break;
case 'groupBy':
const groups = {};
results.forEach(item => {
const value = item[operation.key];
if (!groups[value]) {
groups[value] = [];
}
groups[value].push(item);
});
results = Object.values(groups);
break;
}
});
return results;
};
const queryFn = {
where,
orderBy,
groupBy,
execute
};
return queryFn;
}
上面提供的代码定义了一个名为query的函数,它实现了对数据进行链式查询和处理的功能。以下是对代码的解释:
1. let results = [...data];
:创建一个副本数组 results
,初始值为传入的数据 data
的副本。这样可以避免直接修改原始数据。
2. let operations = [];
:创建一个空数组 operations
,用于存储链式调用的操作。
3. const where = (predicate) => { ... };
:定义 where
函数,它接收一个 predicate
参数作为筛选条件。当调用 where
函数时,将筛选操作对象添加到 operations
数组中,并返回 queryFn
函数,以支持链式调用。
4. const orderBy = (key, desc = false) => { ... };
:定义 orderBy
函数,它接收一个key
参数作为排序依据,desc
参数用于指定排序方式是否为降序(默认为升序)。当调用 orderBy
函数时,将排序操作对象添加到 operations
数组中,并返回 queryFn
函数,以支持链式调用。
5.const groupBy = (key) => { ... };
:定义groupBy
函数,它接收一个key
参数作为分组依据。当调用 groupBy
函数时,将分组操作对象添加到operations
数组中,并返回queryFn
函数,以支持链式调用。
6.const execute = () => { ... };
:定义 execute
函数,用于执行所有操作并返回最终结果。在 execute
函数内部,遍历 operations
数组,根据操作类型进行相应的操作处理。最后返回处理后的results
数组。
7. const queryFn = { ... };
:创建一个名为 queryFn
的对象,它包含了 where
、orderBy
、groupBy
和 execute
这些方法。将它作为最终的返回值,以便进行链式调用。
最后,将queryFn
返回作为query
函数的结果。