黑馬Vue3 + ElementPlus + Pinia 小兔鮮電商項(xiàng)目2023版
黑馬Vue3 + ElementPlus + Pinia 小兔鮮電商項(xiàng)目2023版
download:https://www.51xuebc.com/thread-570-1-1.html
vivo 場景下的 H5無障礙適配理論
一、背景
1.1 無障礙適配認(rèn)知
無障礙(Accessibility)是指為各種才能程度的人們提供公平戰(zhàn)爭等的時(shí)機(jī)和體驗(yàn),以便他們能夠更容易地訪問、運(yùn)用和參與社會(huì)中的各種產(chǎn)品、效勞和環(huán)境。這些人包括身體殘疾、聽力、視覺、認(rèn)知和學(xué)習(xí)障礙等各種才能程度的人。
1.2 無障礙適配緣由
常見的障礙類型包括:視覺障礙、聽覺障礙、認(rèn)知障礙、行動(dòng)障礙。這些“有障礙”的群體,在運(yùn)用軟件時(shí)無法像普通人一樣操作,他們或許看不清,需求更大的字體,或許看不到,需求語音播報(bào),又或許聽不清聽不到,需求依賴視覺反應(yīng),或許肢體操作不便當(dāng),無法自在支配手機(jī)。
所以,國度和企業(yè)需求站在“有障礙”的群體考慮,為各種才能程度的人們提供公平戰(zhàn)爭等的時(shí)機(jī)和體驗(yàn)。
【政策】:2011年《中國殘疾人事業(yè)“十二五”規(guī)劃綱要》指出了,?建立無障礙環(huán)境的主要任務(wù)之?一就是增強(qiáng)信息無障礙建立,并明白了相關(guān)的政策措施。
【容納性】:無障礙適配是一個(gè)重要的設(shè)計(jì)和開發(fā)目的,能夠協(xié)助您的網(wǎng)站或應(yīng)用程序愈加容納和可訪問。
【經(jīng)濟(jì)性】:無障礙適配不只是一種道德義務(wù),也是一種經(jīng)濟(jì)利益,由于它能夠?yàn)槟木W(wǎng)站帶來更普遍的受眾和更好的用戶體驗(yàn),帶動(dòng)業(yè)務(wù)增長。
1.3 無障礙適配引導(dǎo)
除了系統(tǒng)默許支持的大字體、內(nèi)容播報(bào)、語音辨認(rèn)、字幕、語音控制等根底無障礙適配,更多的頁面交互還是需求前端工程師們完成適配,所以開發(fā)者們需求開發(fā)出可辨認(rèn)的web頁面,讓障礙群體能夠正常訪問和運(yùn)用。本文主要針對視障人群停止無障礙適配。
二、無障礙操作
在無障礙開發(fā)前,前端工程師們需求理解下無障礙的操作手勢,站在障礙人群的角度體驗(yàn)操作,這樣才干開發(fā)出更好的交互體驗(yàn)。也能防止因操作錯(cuò)誤招致開發(fā)錯(cuò)誤和反復(fù)開發(fā)。
2.1 讀屏幕軟件
首先我們需求理解下針對視力障礙人員運(yùn)用的讀屏設(shè)備或軟件,常見的讀屏軟件,如下列表:
由于我們是在vivo手機(jī)內(nèi)做挪動(dòng)端安卓手機(jī)無障礙適配,以下的計(jì)劃、案例等引見均是基于Android-TalkBack。
2.2 常用操作手勢
借助 TalkBack 手勢,能夠在 Android 設(shè)備上停止導(dǎo)航和執(zhí)行常用操作,以下操作為安卓9.1版及更高版本,僅在vivo手機(jī)的操作。
三、常用屬性引見
3.1 aria屬性
ARIA全稱“Accessible Rich Internet Applications(可訪問的富互聯(lián)網(wǎng)應(yīng)用)”,是W3C的Web無障礙推進(jìn)組織在2014年3月20日發(fā)布的可訪問富互聯(lián)網(wǎng)應(yīng)用完成指南。是一個(gè)為殘疾人士等提供無障礙訪問動(dòng)態(tài)、可交互Web內(nèi)容的技術(shù)標(biāo)準(zhǔn)。ARIA 用于進(jìn)步運(yùn)用 HTML、CSS、JavaScript、AJAX 和相關(guān)技術(shù)開發(fā)的動(dòng)態(tài)內(nèi)容和高級 UI 控件的輔助功用。ARIA 如今正式成為 HTML5 標(biāo)準(zhǔn)的一局部,還能夠嵌入在常用的 JavaScript 庫中。
3.2 aria狀態(tài)
3.3 role屬性
role將元素標(biāo)志為不同的屬性,常用屬性“button(按鈕),region(圖形)”,依據(jù)定義的不同屬性,播報(bào)不同的內(nèi)容。
3.4 tabindex 屬性
tabindex 屬性的運(yùn)用能夠使得本來無法獲得焦點(diǎn)的元素獲取焦點(diǎn)。目的是為了運(yùn)用戶能夠用鍵盤訪問任何能夠用鼠標(biāo)訪問的元素。我們曉得,運(yùn)用 Tab 鍵能夠按文檔次第 tab 到一切能夠獲取焦點(diǎn)的元素。tabindex 能夠設(shè)置為?-1,?0?或者是任何自然數(shù)。
當(dāng)用戶運(yùn)用 Tab 鍵閱讀頁面時(shí),元素獲取焦點(diǎn)的次第是依照 HTML 代碼里面元素呈現(xiàn)的次第排列的,有時(shí)跟實(shí)踐看到的頁面次第并不分歧。
四、無障礙適配案例
4.1 項(xiàng)目適配案例
1.言語設(shè)置
在全局元素中的 lang 屬性設(shè)置頁面的言語:
英文:
<html lang="en">
中文:
<html lang="zh-CN"></html>
國內(nèi)的中文項(xiàng)目普通需求設(shè)置為中文,假如設(shè)置成了英文,有些數(shù)字會(huì)播報(bào)成英文。
2.層級屬性
假如項(xiàng)目還沒開端適配,則開啟無障礙播報(bào),會(huì)發(fā)現(xiàn)標(biāo)簽div和span默許作為焦點(diǎn)并播報(bào),這樣的話焦點(diǎn)和播報(bào)內(nèi)容就十分分散。
備注:綠色框?yàn)榻裹c(diǎn)標(biāo)志
(1)聚焦播報(bào)
由于div標(biāo)簽會(huì)自動(dòng)播報(bào),所以就算焦點(diǎn)聚焦到外層,但是內(nèi)層還是會(huì)自動(dòng)播報(bào)。
"content" ?tabindex="1"> ?<div class="amount"> ? ?<div class="num">100
<div class="unit">元 ? ?<div class="desc">話費(fèi)充值播報(bào)內(nèi)容:100元話費(fèi)充值。
(2)自定義播報(bào)
但是會(huì)存在div里寫的內(nèi)容和需求播報(bào)的內(nèi)容不分歧,則可在外層tabindex="1"聚焦后,經(jīng)過aria-label寫上自定義內(nèi)容
"content" tabindex="1" aria-label="取得100元的話費(fèi)充值券"> ?<div class="amount"> ? ?<div class="num">100
<div class="unit">元 ? ?<div class="desc">話費(fèi)充值播報(bào)內(nèi)容:取得100元話費(fèi)充值券
3.聚焦款式
聚焦可經(jīng)過tabindex完成,但是聚焦后款式會(huì)有黃色的邊框,可經(jīng)過outline: none去除,但是頁面中的焦點(diǎn)太多,可經(jīng)過全局去除。
在公共css文件里設(shè)置:
*[tabindex] { ? ?outline: none; }
4.圖片播報(bào)
(1)圖片的alt屬性設(shè)置
圖片經(jīng)過img標(biāo)簽完成,假如圖片不可聚焦,則設(shè)置**alt=""**即可。假如可聚焦并需求播報(bào)內(nèi)容,倡議經(jīng)過aria-label設(shè)置。假如運(yùn)用alt,一旦圖片加載不出來,就會(huì)把a(bǔ)lt的內(nèi)容顯現(xiàn)出來,而且alt內(nèi)容沒有款式,在H5頁面上會(huì)顯得很突兀。
"close.png" aria-label="關(guān)閉" alt=""/> <img src="dog.png" alt=""/>
(2)去除圖片默許屬性(圖形)播報(bào)
可在img標(biāo)簽里,將role屬性改為row
"title.png" ?tabindex="1" ?aria-label="超級會(huì)員送您1個(gè)紅包" ?role="row"/>
5.按鈕播報(bào)
通常ui上的按鈕在選中后,需求播報(bào)按鈕內(nèi)容+按鈕+引導(dǎo)操作(如:點(diǎn)按兩次即可激活)
首先需求聚焦(tabindex="1")到節(jié)點(diǎn),然后需求在按鈕上的節(jié)點(diǎn)上寫上role="button",加上這個(gè)屬性后,后面會(huì)自動(dòng)播報(bào)“按鈕,點(diǎn)按兩次即可激活”
案例:div中的按鈕
"1" role="button" class="btn">立刻運(yùn)用
播報(bào)內(nèi)容:立刻運(yùn)用,按鈕,點(diǎn)按兩次即可激活
案例:img中的按鈕
"btn" ?tabindex="1" ?role="button" ?aria-label="開" ?src="open.png"/>
播報(bào)內(nèi)容:開,按鈕,點(diǎn)按兩次即可激活
6.數(shù)字播報(bào)
如:手機(jī)號:181**8805中的星號不能正確播報(bào),而是播報(bào)成乘,數(shù)字播報(bào)成整數(shù)。
錯(cuò)誤播報(bào):一百八十一乘乘乘乘八八零五
需正確播報(bào):幺八幺星號星號星號星號八八零五
可寫一個(gè)公共辦法映射數(shù)字、*號和X號播報(bào)文案,在需求的轉(zhuǎn)換辦法里調(diào)用該辦法構(gòu)成手機(jī)號播報(bào)文案。
公共辦法如下:
function $broadcastNumber(number) { ?if (number === 0) return '零' ?if (!number) return '' ?const numberMap = ['零', '幺', '二', '三', '四', '五', '六', '七', '八', '九'] ?const specialMap = { '*': '星號', 'X': '叉號', 'x': '叉號' } ?return number.toString().split('').map(item => numberMap[item] || specialMap[item] || item).join('') }
7.自定義事情播報(bào)
目前帶有點(diǎn)擊事情的節(jié)點(diǎn),聚焦后會(huì)默許播報(bào)點(diǎn)按兩次即可激活(系統(tǒng)標(biāo)準(zhǔn)),但是這個(gè)引導(dǎo)不夠明白,需求就詳細(xì)交互場景制定播報(bào)內(nèi)容,如:點(diǎn)按兩次即可選中,點(diǎn)按兩次即可翻開紅包等。
計(jì)劃:在click事情節(jié)點(diǎn)里層包裹div,并將焦點(diǎn)tabindex寫在這一層的div上,再自定義播報(bào)的內(nèi)容即可。
"content" tabindex="1" ="select"> ?<div class="amount"> ? ?<div class="num">100
<div class="unit">元 ? ?<div class="desc">話費(fèi)充值播報(bào):100元話費(fèi)充值,點(diǎn)按兩次即可激活
"content" "select"> ?<div class="container" tabindex="1" aria-label="取得100元的話費(fèi)充值券,點(diǎn)按兩次即可選中"> ? ?<div class="amount"> ? ? ?<div class="num">100
<div class= ="unit">元 ? ?<div class="desc">話費(fèi)充值播報(bào):取得100元話費(fèi)充值券,點(diǎn)按兩次即可選中
8.額外內(nèi)容播報(bào)
如:第幾項(xiàng),共幾項(xiàng),點(diǎn)按兩次即可選中
計(jì)劃:可用空div加aria-label完成
"content" "select"> ?<div class="container" :class="{ 'z-active' : code === item.code }" tabindex="1"> ? ?<div v-if="code === item.code" aria-label="已選中">
<div class= ="amount"> ? ? ?<div class="num">{{ item.num }} ? ? ?<div class="unit">元 ? ? ? ?<div class="desc">{{ item.desc }} ? ?<div :aria-label="`第${index+1}項(xiàng),共${list.length}項(xiàng),${code === item.code? '' : '點(diǎn)按兩次即可選中'}`"> ?9.整體播報(bào)
通常整體播報(bào)的內(nèi)容較多,且播報(bào)次第非代碼書寫次第,這個(gè)時(shí)分就需求在外層焦點(diǎn)里,控制播報(bào)的內(nèi)容,主要可經(jīng)過兩種辦法完成,aria-label拼接參數(shù)和aria-labelledby設(shè)置id。
需求播報(bào)的內(nèi)容:話費(fèi)充值券,50元滿減券,滿199元可運(yùn)用,立刻運(yùn)用。
(1)aria-label拼接參數(shù)
可經(jīng)過在外層節(jié)點(diǎn)設(shè)置tabindex=1后,再添加aria-label屬性依照需求的次第添加參數(shù)
案例:
"content" tabindex="1" :aria-label="`${title}${num}元${type}${rule}${btn}`"> ?<div class="left"> ? ?<div class="amount"> ? ? ?<span class="num">{{ num }} ? ? ?<span class="unit">元
<div class="type">{{ type }} ? ?<div class="right"> ? ?<div class="desc"> ? ? ?<div class="title">{{ title }} ? ? ?<div class="rule">{{ rule }} ? ? ? ?<div role="button" class="btn">{{ btn }} ?(2)aria-labelledby設(shè)置id
在外層節(jié)點(diǎn)設(shè)置tabindex=1后,在需求播報(bào)的內(nèi)容節(jié)點(diǎn)里添加id值,并將id值依照需求的次第寫在外層節(jié)點(diǎn)aria-labelledby屬性里
案例:
"content" tabindex="1" aria-labelledby="title amount type rule btn"> ?<div class="left"> ? ?<div id="amount" class="amount"> ? ? ?<span class="num">{{ num }} ? ? ?<span class="unit">元
<div id="type" class="type">{{ type }} ? ?<div class="right"> ? ?<div class="desc"> ? ? ?<div id="title" class="title">{{ title }} ? ? ?<div id="rule" class="rule">{{ rule }} ? ? ? ?<div id="btn" role="button" class="btn">{{ btn }} ?10.部分特殊播報(bào)
如優(yōu)惠券模塊,可整體選中播報(bào)全部優(yōu)惠券內(nèi)容,但內(nèi)部立刻運(yùn)用按鈕又可聚焦播報(bào)跳轉(zhuǎn)。
計(jì)劃:外層聚焦-設(shè)置tabindex=1,播報(bào)整塊內(nèi)容設(shè)置aria-label拼接參數(shù)或aria-labelledby設(shè)置id,內(nèi)層局部內(nèi)容聚焦,聚焦內(nèi)容設(shè)置tabindex=1,不聚焦的局部設(shè)置aria-hidden="true"(不然在選中外層焦點(diǎn)時(shí)分,內(nèi)層非聚焦局部會(huì)反復(fù)播報(bào))。
"content" tabindex="1" aria-labelledby="title amount type rule btn"> ?<div class="left" aria-hidden="true"> ? ?<div id="amount" class="amount"> ? ? ?<span class="num">{{ num }} ? ? ?<span class="unit">元
<div id="type" class="type">{{ type }} ? ?<div class="right"> ? ?<div class="desc" aria-hidden="true"> ? ? ?<div id="title" class="title">{{ title }} ? ? ?<div id="rule" class="rule">{{ rule }} ? ? ? ?<div id="btn" tabindex="1" role="button" class="btn">{{ btn }} ?11. 處理組件設(shè)置aria-labelledby="[id]”后只反復(fù)播報(bào)第一條數(shù)據(jù)的內(nèi)容
因組件被Vue中的模板for循環(huán)調(diào)用,每個(gè)內(nèi)容不一樣,用同一個(gè)id會(huì)招致播報(bào)同一個(gè)內(nèi)容,且沒有key值的辨別,需求處理設(shè)置aria-labelledby="[id]”后只反復(fù)播報(bào)第一條數(shù)據(jù)的內(nèi)容
此時(shí)需求依據(jù)獨(dú)一標(biāo)識(shí)辨別id:可在id后拼接獨(dú)一標(biāo)識(shí)號,如:"amount-${[item.id](http://item.id)}
"
案例:
"content" tabindex="1" :aria-labelledby="`amount-${item.id} desc-${item.id}`"> ?<div id="amount" class="amount">{{ item.amount }}
<div id="desc" class="desc">{{ item.desc }}4.2 組件適配案例
除了詳細(xì)業(yè)務(wù)的適配,還有一些共性的組件問題需求組件庫統(tǒng)一適配,這樣能減少各業(yè)務(wù)單獨(dú)適配的工作量。
任何一個(gè)無障礙組件的適配,都包含播報(bào)內(nèi)容管理、焦點(diǎn)管理兩局部。關(guān)于播報(bào)內(nèi)容管理,簡直一切的組件適配都會(huì)觸及到。無障礙aria role、states普通系統(tǒng)都有本人默許的播報(bào)行為,盡量堅(jiān)持系統(tǒng)默許的播報(bào)。當(dāng)然,也能夠經(jīng)過aria-label定制播報(bào)內(nèi)容。焦點(diǎn)管理主要針對元素會(huì)發(fā)作變化的組件,如彈窗、輪播圖、各類選擇器等。
焦點(diǎn)管理的根本辦法有3種:
tabindex屬性;
aria-hidden屬性;
el.focus()辦法。
tabindex="undefined"即意味著元素不可聚焦,為其他值意味著元素可聚焦。aria-hidden為true,意味著不可聚焦且不播報(bào)。關(guān)于可聚焦的元素,能夠經(jīng)過el.focus()辦法直接聚焦在該元素上。
下面經(jīng)過典型案例來闡明各個(gè)組件是如何處置焦點(diǎn)和播報(bào)內(nèi)容的。另外,由于一個(gè)html中可能屢次運(yùn)用同一個(gè)組件,所以下面的案例都是在不運(yùn)用id屬性的根底上完成適配的。假如一定要在某個(gè)組件運(yùn)用id屬性,記得經(jīng)過隨機(jī)函數(shù)對id屬性做隨機(jī)命名。
1. switch、checkbox、radio組件
這幾個(gè)組件相對簡單,運(yùn)用系統(tǒng)默許的role即可。完成播報(bào)內(nèi)容的適配即可,不需求做焦點(diǎn)管理。
以switch為例:首先是role=switch,然后經(jīng)過aria-check播報(bào)開關(guān)狀態(tài),最后經(jīng)過aria-disabled來播報(bào)能否禁用。
"nx-switch" ?tabindex="-1" ?:aria-checked="!!value" ?:aria-disabled="disabled" ? ="onClick" ?role="switch"> ?<div :style="barStyle">
<div :style="ringStyle">2.彈窗、對話框組件
彈窗組件是一個(gè)相對復(fù)雜的組件,既觸及到焦點(diǎn)管理,也觸及到播報(bào)內(nèi)容管理。經(jīng)過彈窗組件主要引見焦點(diǎn)管理的小技巧。
該組件正在業(yè)務(wù)中的運(yùn)用狀況:
我們的彈窗組件相比照較通用,主要包括標(biāo)題、內(nèi)容、按鈕三個(gè)局部。其中,標(biāo)題、內(nèi)容既能夠經(jīng)過屬性傳入,也能夠經(jīng)過slot傳入。關(guān)于slot傳入的局部,組件不太好控制。在業(yè)務(wù)運(yùn)用過程中,還普遍存在只要內(nèi)容的彈窗。
適配目的:彈窗彈出時(shí)需求自動(dòng)聚焦在標(biāo)題上并播報(bào)。
彈窗焦點(diǎn)次第:彈窗彈出時(shí)需求自動(dòng)聚焦在標(biāo)題上并朗誦標(biāo)題,然后手動(dòng)挪動(dòng)下個(gè)焦點(diǎn)聚焦到闡明文本,最后聚焦到操作按鈕。
(1)焦點(diǎn)管理
首先,需求處理彈窗彈出時(shí)的焦點(diǎn)聚焦問題。由于彈窗組件十分靈敏,所以運(yùn)用場景也十分多樣。關(guān)于屬性傳入的標(biāo)題,組件內(nèi)部能夠獲取到該元素,并完成聚焦播報(bào);關(guān)于slot插入的就顯得無能為力。
關(guān)于slot這種狀況,組件和業(yè)務(wù)商定了一個(gè)屬性,假如業(yè)務(wù)想聚焦在這個(gè)dom元素上,就給該元素添加這個(gè)屬性。組件會(huì)經(jīng)過el.querySelector查詢彈窗的后代元素,在彈窗彈出時(shí)自動(dòng)添加tabindex并完成聚焦播報(bào)。
<nx-popup v-model="isPopupShow.center"> ?<div ? ?nx-popup-aria-auto-focus="true" ? ?aria-label="無障礙播報(bào)測試" ? ?class="nx-popup-center" ?> ? ?Popup Center ?
另外,思索到有業(yè)務(wù)請求彈出時(shí)不自動(dòng)聚焦在彈窗上,所以還提供了屬性,用于關(guān)閉焦點(diǎn)管理功用。
然后,需求處理彈窗關(guān)閉時(shí)的焦點(diǎn)復(fù)原問題。在彈窗彈出前保管當(dāng)前聚焦的元素document.activeElement,關(guān)閉彈窗以后,經(jīng)過el.focus()手動(dòng)聚焦在該元素上。
還剩一個(gè)焦點(diǎn)穿透問題。很多安卓系統(tǒng)aria-modal屬性不起作用,所以焦點(diǎn)還可以穿透彈窗,選中頁面上的元素。
目前組件沒有特別好的方法處置這點(diǎn)。開發(fā)過程中,能夠?qū)π枨笃帘蔚脑靥砑觓ria-hidden=true屬性
(2)播報(bào)內(nèi)容管理
這局部就顯得比擬簡單。關(guān)于slot的狀況,播報(bào)內(nèi)容能夠交給業(yè)務(wù)開發(fā)控制;關(guān)于屬性傳入的狀況,能夠添加組件屬性,為業(yè)務(wù)提供定制化播報(bào)的才能。
3.地址選擇器組件
地址選擇器是一個(gè)滾動(dòng)式交互的組件。在這個(gè)組件的開發(fā)過程中運(yùn)用到了一種小技巧,即不聚焦在某元素上,也能自動(dòng)播報(bào)該元素變化的內(nèi)容。
該組件在業(yè)務(wù)中的運(yùn)用狀況:業(yè)務(wù)開發(fā)沒有對該組件定制化,所以只用思索組件內(nèi)部的適配即可。
適配目的:在彈窗彈出時(shí)自動(dòng)聚焦到標(biāo)題上并播報(bào)。下圖是焦點(diǎn)的排布。
以該圖為例,焦點(diǎn)聚焦在第一列的時(shí)分,播報(bào)“河北省,滑動(dòng)滾輪控件,可上下滾動(dòng)切換”;另外,在每一列滾動(dòng)完畢時(shí),播報(bào)當(dāng)前選中的地址,如“河北省,石家莊市,橋西區(qū)”
(1)焦點(diǎn)管理
同彈窗組件。
(2)播報(bào)內(nèi)容管理
這里的難點(diǎn)就在于每一列滾動(dòng)完畢的時(shí)分,需求播報(bào)變化后的地址,但是此時(shí)焦點(diǎn)還在選中的這列上。
這里添加了一個(gè)躲藏的元素(不在頁面上顯現(xiàn)),并添加屬性aria-live="polite",滾動(dòng)完畢的時(shí)分修正ariaPickerContent的值。假如不想播報(bào)則將ariaPickerContent置為空字符串,彈窗關(guān)閉的時(shí)分記得置為空。
"nx-picker-scroll-aria" aria-live="polite"> ?{{ ariaPickerContent }}
五、總結(jié)
本文是在vivo體系下的無障礙適配理論,主要提煉總結(jié)了一些適配辦法,對內(nèi)外部的無障礙適配工作都有一定的參考和自創(chuàng)價(jià)值。下一步方案豐厚和完善組件庫的適配,沉淀一套高效的適配計(jì)劃,盡量減少開發(fā)人員的適配本錢,進(jìn)步開發(fā)效率。