第44期线上编程实战赛
1 竞赛管理系统¶
let newObj ={}
Object.assign(newObj,obj)
2 汽车私人定制¶
const element = document.querySelector('fieldset[data-uic~="color-compare"]');
const left = document.querySelector("#left");
const right = document.querySelector("#right");
const range = document.querySelector("#range");
// 修改该元素的CSS变量
const change=()=>{
element.style.setProperty("--_c1", left.value);
element.style.setProperty("--_c2", right.value);
element.style.setProperty("--_x", range.value+'%');
}
change()
left.addEventListener('input', change)
right.addEventListener('input', change)
range.addEventListener('input', change)
-
设置CSS变量:
element.style.setProperty('--ca', 'value')
-
获取CSS变量:
element.style.setProperty('--ca')
-
:where()
选择器 -
渐变背景
background-image: linear-gradient(to right, var(--_c1) 0 var(--_x), var(--_c2) 0 var(--_x));
3 花与大海¶
<body>
<!-- App根组件开始 -->
<div id="app">
<div class="box">
<!-- TODO开始: 修改代码,实现点击按钮切换组件 -->
<Component :is="comp"></Component>
<div class="btns">
<button type="button" id="btn1" class="btn" @click="change(0)">花</button>
<button type="button" id="btn2" class="btn" @click="change(1)">大海</button>
</div>
<!-- TODO结束 -->
</div>
</div>
<!-- App根组件结束 -->
<!-- Flower组件开始 -->
<template id="Flower">
<div class="Flower">
<img src="./images/flower.jpg">
</div>
</template>
<!-- Flower组件结束 -->
<!-- Ocean组件开始 -->
<template id="Ocean">
<div class="Ocean">
<img src="./images/ocean.jpg">
</div>
</div>
</template>
<!-- Ocean组件结束 -->
</body>
<script type="module">
const { createApp, ref, reactive, toRefs } = Vue
const app = Vue.createApp({
setup() {
// TODO开始: 添加代码,实现动态组件切换效果
let comp = ref('Flower')
const change = (val) => {
if (val) comp.value = 'Ocean'
else comp.value = 'Flower'
console.log(val);
}
return { change, comp }
// TODO结束
},
});
// Flower组件
app.component("Flower", {
template: "#Flower",
})
// Ocean组件
app.component("Ocean", {
template: "#Ocean",
})
app.mount('#app');
</script>
</html>
-
动态组件
<Component :is="comp"></Component>
-
is
后面跟一个字符串就行,这个字符串是组件的名字 -
注册组件
-
html <template id="Flower"> <div class="Flower"> <img src="./images/flower.jpg"> </div> </template>
-
js app.component("Flower", { template: "#Flower", })
4 网站换皮肤¶
const body = document.querySelector('#body')
const chooseimg = document.querySelector('.chooseimg')
if (localStorage.getItem('src')){
body.style.backgroundImage = `url(${localStorage.getItem('src')})`
box.classList.add('active')
box.classList.remove('default')
}
chooseimg.addEventListener('click', (e) => {
if (e.target.tagName != 'IMG') return
let src = e.target.src
localStorage.setItem('src', src)
body.style.backgroundImage = `url(${src})`
box.classList.add('active')
box.classList.remove('default')
})
clearSkin.addEventListener('click', () => {
body.style.backgroundImage = ''
box.classList.remove('active')
box.classList.add('default')
})
5 进制转换¶
HEX() {
return parseInt(this.request, this.binary).toString(16)
},
DEC() {
return parseInt(this.request, this.binary).toString(10)
},
OCT() {
return parseInt(this.request, this.binary).toString(8)
},
BIN() {
return parseInt(this.request, this.binary).toString(2)
}
parsetInt(string, radix)
,把string按照radix
进制解析为数字Number.prototype.toString(radix)
把数字转换为radix
进制的字符串
6 学生数据请求¶
else if (req.url === '/student' && req.method === 'GET') {
let file = fs.readFileSync('./js/data.js', 'utf8')
send(res, 0, '', file)
} else if (req.url === '/student/add' && req.method === 'POST') {
let body = "";
req.on("readable", () => {
let chunk = "";
if (null !== (chunk = req.read())) {
body += chunk;
}
});
req.on("end", () => {
if (body) {
send(res, 0, '', body)
}
});
}
async function init() {
// 在这里需要获取学生数据并展示到页面中
let res;
// TODO 请求服务器拿到数据,并完成界面渲染,请求学生数据时需要调用上面提供的方法解析响应体中的data数据,调用渲染方法,注意render函数需要传入数组
fetch('/student').then(r => r.json()).then(r => {
console.log(r);
res = parseRes(r.data)
render(res)
submitBtn.addEventListener('click', handleAddStudent)
})
}
async function handleAddStudent(e) {
e.preventDefault();
// TODO 你需要将表单中所有的文本框的值获取到,然后向服务器请求,拿到服务器数据调用渲染方法,注意render函数需要传入数组
let data;
fetch('/student/add', {
method: 'POST',
body: JSON.stringify({
name: nameDom.value,
age: ageDom.value,
phone: phoneDom.value,
})
}).then(res => res.json()).then(res => {
console.log(res);
res=parseRes(res.data)
console.log(res);
render([res])
})
}
7 Markdown编辑器¶
function parseMarkdownToHTML(markdown) {
// TODO: 请完成这个函数
const res = []
const list = markdown.split('\n')
const title = /^#{1,6} (.+)/
const img = /^!\[([^\]]+)\]\(([^\)]+)\)/
const enter = /\n/
const li = /^- (.+)/
const isTable = /^\|/
for (let index = 0; index < list.length; index++) {
let line = list[index]
if (title.test(line)) {
let level=line.split(' ')[0].length
res.push(line.replace(title, `<h${level}>$1</h${level}>`))
} else if (img.test(line)) {
res.push(line.replace(img, '<img src="$2" alt="$1">'))
} else if (line === '') {
res.push('<br>')
} else if (li.test(line)) {
let html = '<ul>'
while (li.test(line)) {
html += line.replace(li, '<li>$1</li>')
line = list[++index]
}
index--
html += '</ul>'
res.push(html)
} else if (isTable.test(line)) {
let html = '<table><tbody>'
while (isTable.test(line)) {
// debugger
let tr = line.split('|').slice(1,-1).map(e => `<td>${e.trim()}</td>`).join('')
tr = `<tr>${tr}</tr>`
html += tr
line = list[++index]
}
index--
html += '</tbody></table>'
res.push(html)
} else {
res.push(line)
}
}
return res.join('<br>');
}
- 换行到底怎么解析?
str.replace('\n', '<br>')
8 中国十大名花¶
index.htm
let useFlower = useFlowerStore();
onMounted(() => {
axios("./js/flowers.json").then((res) => {
useFlower.flowers = res.data;
let item=localStorage.getItem('item')
if(item){
useFlower.select(JSON.parse(item))
}
});
});
store.js
const useFlowerStore = defineStore("useFlowerStore", {
state: () => ({
flowers: [], // 所有花卉信息
selectedFlower: null, // 当前选中的花
}),
// TODO:补全代码实现目标效果
getters: {},
actions: {
select(item){
this.selectedFlower=item
localStorage.setItem('item', JSON.stringify(item))
},
clear(){
this.selectedFlower=null
localStorage.clear()
}
},
// TODOEnd
});
FlowerDetails.js
// TODO:补全代码实现目标效果
const FlowerDetails = {
template: `
<div class="flower" v-if='flowerStore.selectedFlower'>
<h2 class="flower-name">{{flowerStore.selectedFlower.name}}</h2>
<img :src="flowerStore.selectedFlower.image">
<p class="flower-description">花语:{{flowerStore.selectedFlower.language}}</p>
<button type="info" @click='flowerStore.clear'>返回</button>
</div>
`,
setup() {
let flowerStore=useFlowerStore()
return {flowerStore}
},
};
// TODOEnd
FlowerList.js
// TODO:补全代码实现目标效果
const FlowerList = {
template: `
<div class="flower-list" v-if='flowerStore.flowers.length && !flowerStore.selectedFlower'>
<div class="flower-card" v-for='item in flowerStore.flowers' :key='item.id'>
<h2 class="name">{{item.name}}</h2>
<p class="scientific-name">{{item.scientificName}}</p>
<div class="description">{{item.description}}</div>
<button type="primary" @click=flowerStore.select(item)>查看详情</button>
</div>
</div>
`,
setup() {
let flowerStore = useFlowerStore()
// const select=(item)=>{}
return {
flowerStore
}
},
};
// TODOEnd
.value
通常用于处理ref
对象。Pinia 的state
属性默认不是ref
,而是使用reactive
创建的响应式对象。所以你可以直接赋值,而不需要.value
。
9 熟能生巧 -- 记忆函数¶
function memorize(fn) {
let map = new Map()
return function (...arg) {
let str_arg=JSON.stringify(arg)
if (map.has(str_arg)) return map.get(str_arg)
else {
let ans = fn(...arg)
map.set(str_arg, ans)
return ans
}
}
}
- 如何记忆数组?
JSON.stringify(arr)
10 找回密码¶
index.html
¶
const changeStatus = (val) => {
if(typeof val !=='string') return
data.status = val
}
account.vue
¶
<template>
<div class="account container">
<section class="content bgcolor-6">
<span class="input input--juro">
<input
:ref="input"
class="input__field input__field--juro"
type="text"
id="userName"
/>
<label class="input__label input__label--juro" for="input-28">
<span
id="userNameVerify"
class="input__label-content input__label-content--juro"
>用户名</span
>
</label>
</span>
<span class="input input--juro">
<input
:ref="input"
class="input__field input__field--juro"
type="text"
id="idNum"
/>
<label class="input__label input__label--juro" for="input-29">
<span
id="idNumVerify"
class="input__label-content input__label-content--juro"
>身份证号</span
>
</label>
</span>
</section>
<el-button type="primary" id="nextStep" @click="next">下一步</el-button>
</div>
</template>
<script>
const { ref, onMounted, defineEmits } = Vue;
module.exports = {
name: "account",
setup(props,{emit}) {
const next = () => {
let flag=true;
if (/^[\d\w\_]{3,5}$/.test(inputs.value[0].value)) {
document.querySelector("#userNameVerify").classList.add("right");
document.querySelector("#userNameVerify").classList.remove("wrong");
document.querySelector("#userNameVerify").innerText = "用户名";
} else {
document.querySelector("#userNameVerify").classList.remove("right");
document.querySelector("#userNameVerify").classList.add("wrong");
document.querySelector("#userNameVerify").innerText = "用户名不合法";
// context 是 setup 函数的第二个参数。它包含了一些组件相关的上下文信息,包括 attrs、slots 和 emit。
emit("change", "error");
flag=false
}
let shenfen = inputs.value[1].value;
let region = shenfen.slice(0, 6);
if (
shenfen.length !== 18 ||
!/^[1-9][\d]{5}$/.test(region) ||
!/^(19|20|21)[\d]{2}$/.test(shenfen.slice(6, 10)) ||
!/^\d{7}$/.test(shenfen.slice(10, 17)) ||
!/^[\dX]$/
) {
document.querySelector("#idNumVerify").classList.remove("right");
document.querySelector("#idNumVerify").classList.add("wrong");
document.querySelector("#idNumVerify").innerText = "身份证号不合法";
emit("change", "error");
flag=false
} else {
document.querySelector("#idNumVerify").classList.add("right");
document.querySelector("#idNumVerify").classList.remove("wrong");
document.querySelector("#idNumVerify").innerText = "身份证号";
}
if(flag){
emit("change", "success");
emit("show", "check");
emit("next", 1);
emit("change", "process");
}
};
// ***此部分代码不用修改***
//#region
// ref 被设置为一个函数 input,这意味着 Vue 会在组件渲染时调用这个函数
// 并将相应的 DOM 元素作为参数传递给它。
const inputs = ref([]);
const input = (el) => {
inputs.value.push(el);
};
onMounted(() => {
inputs.value.map((el) => {
if (el.value.trim() != "") {
el.parentNode.classList.add("input--filled");
}
el.onfocus = function () {
el.parentNode.classList.add("input--filled");
};
el.onblur = function () {
if (this.value.trim() != "") {
el.parentNode.classList.add("input--filled");
} else {
el.parentNode.classList.remove("input--filled");
}
};
});
});
//#endregion
// **********************
return {
input,
next,
};
},
};
</script>
<style scoped></style>
steps.vue
¶
<template>
<div class="steps">
<el-steps
align-center
:active="props.active"
:process-status="props.status"
finish-status="success"
>
<el-step title="账号核实" description="输入用户名和身份证号"></el-step>
<el-step title="验证身份" description="请确认您是真人"></el-step>
<el-step title="修改密码" description="输入要修改的密码"></el-step>
<el-step title="成功" description="成功找回密码"></el-step>
</el-steps>
</div>
</template>
<script>
module.exports = {
// TODO:补全代码实现目标效果
name:'steps',
props:['active', 'status'],
setup(props, { emit }) {
return { props };
},
};
</script>
<style scoped>
</style>
check.vue
¶
<template>
<div class="check" v-loading="loading" element-loading-text="验证中...">
<div class="robot" @click="inputCheck">
<input type="checkbox" />
<span>确认您是真人</span>
</div>
</div>
</template>
<script>
const { ref} = Vue;
module.exports = {
name: "check",
setup(props, { emit }) {
// TODO:补全代码实现目标效果
const loading = ref(false);
console.log();
const inputCheck = () => {
loading.value = true;
setTimeout(() => {
loading.value = false;
emit("change", "success");
emit("show", "modify");
emit("next", 2);
emit("change", "process");
}, 1500);
};
return {
inputCheck,
loading,
};
},
};
</script>
<style scoped></style>
modify.vue
¶
<template>
<div class="modify container">
<section class="content bgcolor-6">
<span class="input input--juro">
<input
:ref="input"
class="input__field input__field--juro"
type="text"
id="passwordOne"
/>
<label class="input__label input__label--juro" for="input-28">
<span
id="passwordOneVerify"
class="input__label-content input__label-content--juro"
:class="{
wrong: rightPasswd === 2,
right: rightPasswd === 1,
}"
>{{ rightPasswd === 2 ? "您输入的密码不合法" : "请输入密码" }}</span
>
</label>
</span>
<span class="input input--juro">
<input
:ref="input"
class="input__field input__field--juro"
type="text"
id="passwordTwo"
/>
<label class="input__label input__label--juro" for="input-29">
<span
id="passwordTwoVerify"
class="input__label-content input__label-content--juro"
:class="{ wrong: twoEqual === 2, right: twoEqual === 1 }"
>{{
twoEqual === 2 ? "两次输入的密码不一致" : "请再次输入密码"
}}</span
>
</label>
</span>
</section>
<el-button type="primary" id="alter" @click="checkModify">修改</el-button>
</div>
</template>
<script>
const { ref, onMounted } = Vue;
module.exports = {
name: "modify",
setup(props, { emit }) {
// TODO:补全代码实现目标效果
console.log(emit);
const checkPasswd = (password) => {
// debugger
if (password.length < 6 || password.length > 12) return false;
if (!/[A-Z]/.test(password) || !/[a-z]/.test(password)) return false;
if (!/\d/.test(password)|| !/[_@$!%*?&]/.test(password)) return false;
return true;
};
// ***此部分代码不用修改***
//#region
const inputs = ref([]);
const input = (el) => {
inputs.value.push(el);
};
onMounted(() => {
inputs.value.map((el) => {
if (el.value.trim() != "") {
el.parentNode.classList.add("input--filled");
}
el.onfocus = function () {
el.parentNode.classList.add("input--filled");
};
el.onblur = function () {
if (this.value.trim() != "") {
el.parentNode.classList.add("input--filled");
} else {
el.parentNode.classList.remove("input--filled");
}
};
});
});
//#endregion
// **********************
const rightPasswd = ref(0);
const twoEqual = ref(0);
const checkModify = () => {
if (checkPasswd(inputs.value[0].value)) {
rightPasswd.value = 1;
} else {
rightPasswd.value = 2;
emit("change", "error");
}
if (inputs.value[0].value == inputs.value[1].value) {
twoEqual.value = 1;
if (rightPasswd.value === 1) {
console.log(emit);
emit("change", "success");
emit("show", "success");
emit("next", "3");
emit("change", "success");
}
} else {
twoEqual.value = 2;
}
};
return {
input,
rightPasswd,
twoEqual,
checkModify,
};
},
};
</script>
<style scoped>
</style>
-
在 Vue 3 中,
setup
函数可以接收两个参数: -
props
:这是一个对象,包含传递给组件的属性。props
是响应式的,可以在setup
函数中直接使用。 context
:这是一个对象,包含了组件的上下文信息。它有以下三个属性:attrs
:包含传递给组件但未被声明为props
的属性。这些属性通常会被应用到组件的根元素上。slots
:包含传递给组件的插槽内容。emit
:用于触发自定义事件的方法。
因此,setup
函数的完整签名如下:
<script>
module.exports = {
// TODO:补全代码实现目标效果
name:'steps',
props:['active', 'status'],
setup(props, { emit }) {
return { props };
},
};
</script>
-
要使用
props
,必须声明props:['active', 'status']
,不然不会触发响应式 -
如果属性名包含特殊字符、空格、连字符(-)等,或者以数字开头,就需要加引号
<span
id="passwordOneVerify"
:class="{
'input__label-content': true,
'input__label-content--juro': true,
wrong: rightPasswd === 2,
right: rightPasswd === 1,
}"
>请输入密码</span>