1.動態的Tab欄
日常在使用移動端 APP 或訪問 PC 端網站的時候,常常發現在一些有工具欄或者 Tab 欄的頁面會有頂欄固定的效果。簡單來說,在頁面未開始滾動時頂欄處在其原有的位置上,當頁面向下滾動一定區域后,頂欄會跟隨滾動固定在頁面上方。
1.1 題目要求
請在 style.css 文件中補全代碼。
- 當用戶向下滾動的高度沒有超過標題欄(即 .heading 元素)的高度時,保持 Tab 欄在其原有的位置。當滾動高度超過標題欄的高度時,固定顯示 Tab 欄在網頁頂部。
完成后效果如下
1.2 題目分析
第一題比較簡單,就是讓我們在style.css中添加代碼實現定位的效果,想到定位我們腦子里應該想到的是:position,沒錯就是用它,如果你忘記了它有哪些用法,請看下面的表格:
定位 | 作用 |
---|---|
static | 元素處于正常文檔流中,不受 top, right, bottom, left 影響。 |
relative | 元素相對于其正常位置進行定位。元素仍保持正常文檔流,但會對其進行相對調整。 |
absolute | 元素相對于最近的已定位祖先元素進行定位。如果沒有已定位的祖先元素,則相對于最初的包含塊(通常是 <html> 元素)進行定位。 |
fixed | 元素相對于視口進行定位,即使頁面滾動,元素位置也不會改變 |
sticky | 元素根據用戶的滾動位置在父元素中定位。在元素在屏幕中可見時,它的位置是相對定位的,當頁面滾動超出范圍時,它的位置是固定的。 |
當我們知道各個屬性的作用后,在根據題目需要達到的效果,很明顯這里要使用的是:sticky
1.3 源代碼
/* TODO: 請在此補充代碼實現tab欄動態固定 */position: sticky;top: 0;
2.地球環游
“地球漫游”:一款基于 CSS 動畫的小型網頁應用,讓您身臨其境地感受地球繞著太陽公轉的奇妙旅程。通過這個應用,您可以觀察地球繞著太陽的運動軌跡和速度,感受到宇宙的浩瀚和神秘。
2.1 題目要求
找到 css/style.css
文件中的 TODO 部分,完成以下目標:
給 .earth-con
元素添加動畫,設置如下:
- 動畫名稱:
orbit
- 動畫時間: 36.5 秒
- 速度函數:線性
- 播放方式:無限循環
完成后效果如下:
2.2 題目分析
這一題只要你知道css動畫的使用方法,簡直就是送分,所有動畫的要求都已經給你了,而且還標注出來了動畫的名稱,直接在對應的css部分添加動畫代碼即可。
2.3 源代碼
/* TODO:待補充代碼,添加動畫 */animation: orbit 36.5s linear infinite;
3.迷惑的this
團隊開發中為了解決變量相互覆蓋的問題,會將相關的功能的涉及到變量收編到一個對象內。但使用對象收編變量后需要注意 this
合理使用。
3.1 題目要求
完善 js/index.js 中的 handle 函數中的 TODO 部分,實現以下功能:
- 為輸入框(即 this.inputEl)綁定 input 事件,當輸入框的值發生變化時,調用已經提供的 handleInput 方法進行搜索處理,注意 handleInput 方法調用時的 this 指向應為 search 對象本身。
完成后效果如下:
3.2 題目分析
根據題目的名稱可以看出來這一題應該是與this相關的問題,js文件中需要用到的dom元素和函數都已經給我們寫好了,只需要我們給input綁定一個input事件,我們相當然的就會寫出這樣的代碼:
handle() {// TODO:待補充代碼this.inputEl.addEventListener('input', this.handleInput)},
但是運行發現不對,達不到效果,錯誤的原因就是忽略了this的指向問題,當你使用addEventListener
將一個函數作為事件處理程序附加到元素時,該函數會失去其原始上下文,函數內部的this
將指向觸發事件的元素。我們可以打印此時的this看看:
可以看到此時的this指向已經變成了input這個dom元素了,他的身上并沒有hanleInput()這個方法,此時我們就要使用bind來修改this的指向。在面向對象中bind是很重要的,關乎到整個class對象的this問題。
3.3 源代碼
handle() {// TODO:待補充代碼//使用bind來糾正 this的指向this.inputEl.addEventListener('input', this.handleInput.bind(this))},
4.魔法失靈了
oh ~ 糟糕 😰 ,dr.小藍正在研究一項偉大的發明,實驗進行中控制重要的元素 Magic 的按鈕突然失靈了,快來用你的魔法幫助 dr.小藍吧。
4.1 題目要求
找到 index.html
中 TODO 部分,正確修復代碼使 data
對象恢復響應式特性,即點擊頁面上的 - 與 + 按鈕可以改變 value
的值。
正確實現后效果如下:
4.2 題目分析
這個題目主要是按鈕事件失靈了,如果不仔細看可能一時半會看不出來問題,其實就是
//TODO:待修復代碼let { value }={ ...data }
這行代碼將value從data中結構出來后,value就失去了響應式效果了,而且仔細看的話,可以看到題目中引入了toRefs,但是沒有使用,toRefs的作用就是讓結構出來的元素不失去響應式,在日常開發中主要是為了簡化代碼,如果不結構,在html中就要使用這種:data.value的形式渲染數據。
4.3 源代碼
//TODO:待修復代碼let { value } = toRefs(data) //結構賦值將value失去的響應式//利用toRefs 恢復響應式
5.燃燒你的卡路里
為了瘦,為了美,為了穿衣服好看,小藍決定減肥,管住嘴邁開腿,燃燒卡路里不止需要運動,還需要合理制定飲食規劃。為了瘦,為了美,為了穿衣服好看,小藍決定減肥,管住嘴邁開腿,燃燒卡路里不止需要運動,還需要合理制定飲食規劃。
5.1 題目要求
請在 js/index.js
和 index.html
文件中補全代碼,完成以下目標:
-
點擊“定制方案”按鈕后,彈出側滑頁面,所使用的組件為
el-drawer
參數 說明 類型 默認值 v-model 是否顯示 Drawer boolean false -
封裝
sortItem
函數,按照食物屬性名稱將早餐/午餐/晚餐的數組數據從大到小排序,然后找到排序后的數組中第一個不大于對應攝入量上限的食材對象,并將其返回。
sortItem
參數:
arr
:早餐/午餐/晚餐的數據。pro
:食物屬性名稱,可取值carbohydrate
/protein
/fat
。compare
:糖類、蛋白質、脂肪的對應攝入量上限值,作為比較條件用的,已傳入具體值。
sortItem
返回值示例
{ "name": "雞蛋","carbohydrate": 1.5,"protein": 12.7,"fat": 9,"kcal": 138,"weight": 100
}
早餐/午餐/午餐中數據字段說明如下:
名稱 | 說明 |
---|---|
name | 食材名稱 |
carbohydrate | 碳水化合物(單位:克) |
protein | 蛋白質(單位:克) |
fat | 脂肪(單位:克) |
kcal | 食物熱量(單位:克) |
weight | 重量(單位:克) |
完成后,點擊定制方案按鈕,效果如下:
5.2 題目分析
第一個要求很簡單,就是在el-drawer上綁定它的開關屬性,在觸發按鈕事件時將其改成 true即可
第二個要求涉及到的是排序以及遍歷,排序我們直接使用 sort對屬性名稱進行排序即可,然后再遍歷查找到對應的元素進行比較返回對應的值即可。
5.3 源代碼
第一處:
第二處:
這里提供二種方法,如果對js的array方法熟練的可以直接使用方法,不熟練的可以遍歷
const sortItem = (arr, pro, compare) => {// TODO 根據 compare 匹配食材對象后返回這個對象// 按照食物屬性名稱將早餐/午餐/晚餐的數組數據從大到小排序,//然后找到排序后的數組中第一個不大于對應攝入量上限的食材對象,并將其返回。//第一種const sortedArr = arr.sort((a, b) => b[pro] - a[pro]);const optimalItem = sortedArr.find(item => item[pro] < compare);return optimalItem;//第二種arr.sort((a, b) => b[pro] - a[pro])for (const item of arr) {if (item[pro] < compare) {return item}}}
6.司齡統計
M 公司馬上要進行周年慶典活動了,公司讓小藍做一個員工司齡統計,用來根據司齡給大家發放紀念品,便于計算紀念品費用。但是眼看時間到了小藍來不及編寫,請熱心的你幫他完成這個任務吧~
6.1 題目要求
找到 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。
完成后效果如下:
6.2 題目分析
這個題目首先第一步就是要對數據進行重新改裝,將數據按照age進行分組改裝,要實現其實比較簡單,直接遍歷插入即可
第二步是要設置Echarts的X軸數據和Y軸數據,x軸的數據是司齡,也就是age,但是有個要求是要進行升序排序,這里又用到了sort排序,y軸的數據是人數,也就是對應的age數組的長度,因為前面已經進行了排序,我們直接遍歷返回數組長度就行。
6.3 源代碼
// 按照年齡分組的函數
const groupByAge = (peoples) => {// TODO:待補充代碼,按照年齡進行分組//按照age進行排序const data = {}peoples.forEach((item) => {//判斷data中是否存在if (!data[item.age]) {data[item.age] = []}data[item.age].push(item)})return data
}// TODO: 設置 Echars X 軸數據 xAxisData 和 Y 軸數據 seriesDataxAxisData.value = Object.keys(groupedPeople.value).sort((a, b) => a - b)seriesData.value = Object.values(groupedPeople.value).map((item) => {return item.length})
7.不翼而飛的余額
小藍開發了一個 web3 錢包,用于在瀏覽器中管理以太坊賬戶。為了方便用戶使用,小藍決定將錢包分為兩個頁面:
- 存款頁面,用于用戶存款。
- 錢包頁面,用于查看賬戶余額。
7.1 題目要求
完善 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。
完成后效果:
7.2 題目分析
- 第一步就是配置路由,如果不會的建議學習一下vue-router:https://router.vuejs.org/zh/guide/essentials/history-mode.html,這里二種模式都是可以使用的,按照要求配置即可,沒什么難的。
- 第二步是再DepositPage組件中修改balance的數據,需要保持組件間的數據統一性,這里使用了Pinia倉庫,不過這里不知道pinia也沒事,這里唯一要注意的是數據的正確性,題目要求是要正整數,所以做一個判斷即可,最后加上后清空input框。
7.3 源代碼
第一步:
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}]})
第二步:
第三步:
setup() {const depositAmount = Vue.ref() // 輸入框中的的值->存款金額const store = useMoneyStore() // 引入 store// TODO:待補充代碼,完善點擊存款按鈕事件function deposit() {if (!isNaN(depositAmount.value) && depositAmount.value >= 0) {store.balance += depositAmount.valuedepositAmount.value = null}}return {deposit,depositAmount,store}}
8.個性化推薦
當下,移動互聯網技術和智能手機的發展,使得采集用戶數據的能力變得空前強大,無時無刻,無所不在。擁有這些數據后,全行業的個性化推薦能力變得更加容易實現,不論是淘寶京東,還是今日頭條,無疑是這個時代的最大受益者。個性化推薦的本質是根據不同的人群,將最有可能感興趣的內容優先推薦給相應的用戶,最大限度的提高轉化率。
8.1 題目要求
請在 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 中。 在代碼更新后,請記得重啟服務器!
8.2 題目分析
初看題目,我們要寫的地方都在js文件中,如果會nodejs的人,應該能讀懂代碼,我簡單解釋一下,(如果能看懂可以跳過)這里就是啟動服務在8080端口,如果訪問的是:‘/’,則會讀取index.html文件相應給客戶端,而在index.html中有一個表單,它的提交地址是:‘/customized’,所以當submit按鈕單擊后就會跳到此頁面,并攜帶這些數據。
此時我們需要相應對應的頁面給客戶端,這里就需要進行判判表單元素有沒有數據了,如果沒有則相應一段提示文本,否則相應對應的提示,這里的提示還算簡單,主要看怎么根據對應的數據解析出所有需要的推薦數據。
8.3 源代碼
// TODO: 補充個性化頁面處理代碼//1.讀取文件const customizedPage = fs.readFileSync(path.join(__dirname, '../customized.html'), {encoding: 'utf8'})let indexHtml = ''if (interested.length === 0) {indexHtml = customizedPage.replace('<body></body>', `<body><div class="unselect">你還未選擇任何感興趣的標簽!</div></body>`)} else {//2.首先查出所有的tag以及附帶的tag (將interested轉為數組)let tags = Array.isArray(interested) ? interested : [interested]tags.forEach((item) => {const found = data.find((foundData) => {return foundData.tag == item})//查出來后再去對比relevanceif (found && found.tag != 'HTML5') {//小坑,found.relevance.forEach((relevance) => {if (!tags.includes(relevance)) {tags.push(relevance)}})}})let html = ''tags.forEach((item) => {const found = data.find((foundData) => {return foundData.tag == item})if (found) {html += `<div class="interest"><div class="tag">${found.tag}</div><div>${found.content}</div></div>`}})indexHtml = customizedPage.replace('<body></body>', `<body>${html}</body>`)}res.writeHead(200, { 'Content-Type': 'text/html' })res.write(indexHtml)res.end()
9.貪吃蛇
貪吃蛇作為一款經典休閑益智類游戲,通過控制蛇頭方向吃蛋,從而使得蛇變得越來越長。在 90 年代擁有一部可以玩貪吃蛇的手機可以玩上一整天,如今可玩的游戲越來越多,但是當時玩一天的快樂再也找不回了。
9.1 題目要求
找到 index.js
文件中的 nextStep
函數,完成函數中的 TODO 部分:
- 根據當前蛇的移動方向(
this.direction
)以及蛇身塊的大小(this.size
),計算新的蛇頭位置,更新蛇身坐標數組 (this.snakeBody
),即可實現蛇的正確移動。蛇的移動和增加蛇的長度代碼已提供。
蛇身坐標示例如下:
[{ left: 2, top: 0 }, { left: 1, top: 0 }, { left: 0, top: 0 }]`
蛇的身體是由多個坐標點組成的,每個坐標點包含了 left
和 top
屬性,分別表示在游戲界面中的水平和垂直位置,第一個坐標表示當前蛇頭的位置。
完成后,效果如下:
9.2 題目分析
這一題乍一看挺難的,代碼很長,但其實通過觀察發現,其實大多數代碼都已經寫好了,我們只需要拿到蛇頭的方向對它的坐標進行替換就行,后面身子部分啥的坐標都不用管。所以我們只要拿到蛇頭的坐標,判斷其目前的方向,坐標加上自身的大小(size)即可。
9.3 源代碼
// 移動蛇的頭部nextStep() {// TODO:待補充代碼const snake = this.snakeBodyconst head = { ...snake[0] }switch (this.direction) {case 'right':head.left += this.sizebreakcase 'down':head.top += this.sizebreakcase 'left':head.left -= this.sizebreakcase 'up':head.top -= this.sizebreak}this.snakeBody.unshift(head) // 在頭部插入新坐標this.snakeBody.pop() // 刪除尾部坐標this.render() // 重新渲染蛇身體}
10.自定義表單驗證
自定義表單驗證器是一種在 Web 開發中常用的技術,用于驗證用戶輸入的數據是否符合特定的規則或要求。通過自定義表單驗證器,我們可以對表單字段進行驗證,并在用戶提交表單之前檢查數據的有效性。
10.1 題目要求
- 完成
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 | 驗證失敗時的錯誤信息 |
完成后示例效果如下:
10.2 題目分析
第一問,改變父組件中的數據,我們首先應該想到的是自定義事件,子傳父嘛,但是通過觀察后發現父組件好像并沒有定義自定義事件,而且題目要求我們只修改子組件,然后通過觀察可以知道子組件引入了emit,而父組件使用了v-model對表單進行了綁定,此時我們就可以使用v-model來進行通信,如果對如果使用v-model來通信不了解的,可以查看這篇文章,里面列舉了vue3組件間的通信方式:https://blog.csdn.net/m0_64642443/article/details/131787640
第二問是郵箱正則沒啥好說的,不會的可以先去學習一下正則怎么寫喔。
第三問:題目要求中也寫出來了數據從,props.rules和props.formData中拿,我們拿到數據對其進行驗證然后返回相應的錯誤信息就行(message)。
10.3 源代碼
第一問:
// TODO:目標 1 當輸入框的值變化時,觸發 input 事件更新父組件的 v-model 值watch(inputValue, (newValue) => {emit('update:value', newValue)})// TODO:end
第二問:
const is_email = (val) => {// TODO:目標 2 待補充代碼const emailRegex = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z]{2,4}$/return emailRegex.test(val)
}
第三問:
// TODO:目標 3 編寫通用的表單驗證規則,并將錯誤信息放置到 errors 對象中for (const field in props.rules) {const fieldRules = props.rules[field]for (const rule of fieldRules) {if (rule.required && !props.formData[field]) {errors.value[field] = rule.messagebreak}if (rule.type && !validateByType(rule.type, props.formData[field])) {errors.value[field] = rule.messagebreak}if (rule.min && props.formData[field].length < rule.min) {errors.value[field] = rule.messagebreak}if (rule.max && props.formData[field].length > rule.max) {errors.value[field] = rule.messagebreak}}}// 添加對 nickname 字段的非空判斷if (props.rules.nickname && !props.formData.nickname) {errors.value.nickname = '昵稱不能為空'}}if (rule.type && !validateByType(rule.type, props.formData[field])) {errors.value[field] = rule.messagebreak}if (rule.min && props.formData[field].length < rule.min) {errors.value[field] = rule.messagebreak}if (rule.max && props.formData[field].length > rule.max) {errors.value[field] = rule.messagebreak}}}