[langnostic] publish: 0.0.8
This commit is contained in:
parent
d2530e9d93
commit
aaabb7821c
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
],
|
||||
"pt-BR": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
],
|
||||
"pt-BR": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
],
|
||||
"pt-BR": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
],
|
||||
"pt-BR": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
],
|
||||
"pt-BR": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
],
|
||||
"pt-BR": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
],
|
||||
"pt-BR": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"217d5db8",
|
||||
"26e3ffe5",
|
||||
"3343e483",
|
||||
"f61f0dc0",
|
||||
"4b8f8de9",
|
||||
"4ceffda9",
|
||||
"76727e36",
|
||||
"4de859da",
|
||||
"6741f5e3",
|
||||
"cc8ddea1",
|
||||
"9787c830",
|
||||
"38b458ca",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"217d5db8",
|
||||
"26e3ffe5",
|
||||
"3343e483",
|
||||
"f61f0dc0",
|
||||
"4b8f8de9",
|
||||
"4ceffda9",
|
||||
"76727e36",
|
||||
"4de859da",
|
||||
"6741f5e3",
|
||||
"cc8ddea1",
|
||||
"9787c830",
|
||||
"38b458ca",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
],
|
||||
"pt-BR": [
|
||||
"217d5db8",
|
||||
"26e3ffe5",
|
||||
"3343e483",
|
||||
"f61f0dc0",
|
||||
"4b8f8de9",
|
||||
"4ceffda9",
|
||||
"76727e36",
|
||||
"4de859da",
|
||||
"6741f5e3",
|
||||
"cc8ddea1",
|
||||
"9787c830",
|
||||
"38b458ca",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
],
|
||||
"pt-BR": [
|
||||
"f9802859",
|
||||
"dff45f7a"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
],
|
||||
"pt-BR": [
|
||||
"d99f611c",
|
||||
"996ef906",
|
||||
"e07bfd45",
|
||||
"b4707fc8"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"frontmatter": {
|
||||
"title": "4696c894",
|
||||
"excerpt": "74953e6b"
|
||||
},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"cd151398",
|
||||
"e7118b06",
|
||||
"71b50cc3",
|
||||
"1d712abb",
|
||||
"e1c29a66",
|
||||
"add698fb",
|
||||
"1ffa43f1"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"cd151398",
|
||||
"e7118b06",
|
||||
"71b50cc3",
|
||||
"1d712abb",
|
||||
"e1c29a66",
|
||||
"add698fb",
|
||||
"1ffa43f1"
|
||||
],
|
||||
"pt-BR": [
|
||||
"cd151398",
|
||||
"e7118b06",
|
||||
"71b50cc3",
|
||||
"1d712abb",
|
||||
"e1c29a66",
|
||||
"add698fb",
|
||||
"1ffa43f1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"c0257a0c",
|
||||
"4e9df497",
|
||||
"c3ea8b25"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"c0257a0c",
|
||||
"4e9df497",
|
||||
"c3ea8b25"
|
||||
],
|
||||
"pt-BR": [
|
||||
"c0257a0c",
|
||||
"4e9df497",
|
||||
"c3ea8b25"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"26e3ffe5",
|
||||
"11c16fdc",
|
||||
"42eddc89",
|
||||
"b40e1f28",
|
||||
"ea50534e",
|
||||
"3a89f1f3",
|
||||
"c0bdc660"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"26e3ffe5",
|
||||
"11c16fdc",
|
||||
"42eddc89",
|
||||
"b40e1f28",
|
||||
"ea50534e",
|
||||
"3a89f1f3",
|
||||
"c0bdc660"
|
||||
],
|
||||
"pt-BR": [
|
||||
"26e3ffe5",
|
||||
"11c16fdc",
|
||||
"42eddc89",
|
||||
"b40e1f28",
|
||||
"ea50534e",
|
||||
"3a89f1f3",
|
||||
"c0bdc660"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"frontmatter": {},
|
||||
"content": {
|
||||
"source": {
|
||||
"locale": "en-US",
|
||||
"hashes": [
|
||||
"b9033719",
|
||||
"bcf6251"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"zh-CN": [
|
||||
"b9033719",
|
||||
"bcf6251"
|
||||
],
|
||||
"pt-BR": [
|
||||
"b9033719",
|
||||
"bcf6251"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
|
||||
## Solução
|
||||
|
||||
### Design de Configuração/API
|
||||
|
||||
Parte da complexidade da construção de um componente é projetar sua API. A função `accordion` aceita um elemento raiz, `$rootEl`, onde as seções do acordeão serão inseridas. O segundo parâmetro da função `accordion` é um objeto usado para armazenar as opções de configuração. No mínimo, precisaremos das seguintes opções:
|
||||
|
||||
* `items`: Uma lista de objetos de itens. Cada item é um objeto com os campos:
|
||||
* `value`: Um identificador único para o item do acordeão.
|
||||
* `title`: O rótulo de texto a ser exibido no título do acordeão.
|
||||
* `contents`: O conteúdo a ser exibido quando a seção é expandida.
|
||||
|
||||
Ao contrário da nossa abordagem típica de Vanilla JS, optamos por não manter nenhum estado em JavaScript desta vez e, em vez disso, confiamos no DOM para rastrear o estado de cada seção do acordeão e expandir/recolher os elementos apropriados com base no estado desse acordeão.
|
||||
|
||||
A função `accordion` chama as funções `init` e `attachEvents` para configurar o componente do acordeão, renderizando os elementos DOM e anexando os ouvintes de eventos necessários.
|
||||
|
||||
### `init`
|
||||
|
||||
Esta função configura os elementos DOM que permanecem durante todo o ciclo de vida do componente, ou seja, eles nunca serão destruídos. As seções do acordeão (títulos e conteúdos) são renderizadas.
|
||||
|
||||
### `attachEvents`
|
||||
|
||||
Apenas um único ouvinte de evento é necessário neste componente, que é o evento `click`, a ser adicionado ao elemento raiz. Fazemos uso da Delegação de Eventos para que apenas um único ouvinte de evento precise ser adicionado e funcione para todo o seu conteúdo filho. No entanto, devemos ter cuidado ao verificar em qual elemento está sendo clicado e garantir que estamos respondendo apenas quando o título é clicado e não o conteúdo.
|
||||
|
||||
Quando um clique é acionado no título do acordeão, precisaremos girar o ícone e alternar o atributo `hidden` no conteúdo do acordeão.
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
title: Acordeão
|
||||
excerpt: >-
|
||||
Crie um componente de acordeão que exibe uma lista de seções empilhadas
|
||||
verticalmente, cada uma contendo um título e um trecho de conteúdo
|
||||
---
|
||||
|
||||
Crie um componente de acordeão que exibe uma lista de seções empilhadas verticalmente, cada uma contendo um título e um trecho de conteúdo. Algum HTML é fornecido como conteúdo de exemplo, juntamente com um ícone de chevron.
|
||||
|
||||
## Requisitos
|
||||
|
||||
* Por padrão, todas as seções são recolhidas e estão ocultas da visualização.
|
||||
* Clicar no título de uma seção alterna o conteúdo.
|
||||
* Se a seção estiver recolhida, a seção será expandida e o conteúdo será exibido.
|
||||
* Se a seção estiver expandida, a seção será recolhida e o conteúdo será ocultado.
|
||||
* As seções são independentes umas das outras.
|
||||
|
||||
## Exemplo
|
||||
|
||||
Experimente um [exemplo de um componente de acordeão](https://www.w3.org/WAI/ARIA/apg/example-index/accordion/accordion.html).
|
||||
|
||||
## Notas
|
||||
|
||||
* O foco desta questão é a funcionalidade, não o estilo. Não gaste muito tempo escrevendo CSS personalizado.
|
||||
* Você pode modificar a marcação (por exemplo, adicionar `id`s, atributos de dados, substituir algumas tags, etc.) e usar a renderização do lado do cliente.
|
||||
* Você pode querer pensar em maneiras de melhorar a experiência do usuário do aplicativo e implementá-las (você ganha crédito de bônus por fazer isso durante as entrevistas).
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
## Acessibilidade
|
||||
|
||||
Elementos interativos precisam ser focáveis, então usaremos um `<button>` para o título.
|
||||
|
||||
O [Guia de Práticas de Criação ARIA para Accordion](https://www.w3.org/WAI/ARIA/apg/patterns/accordion) tem uma longa lista de diretrizes para as funções, estados e propriedades ARIA a serem adicionadas aos vários elementos de um acordeão. [Accordion II](/questions/user-interface/accordion-ii) e [Accordion III](/questions/user-interface/accordion-iii) se concentrarão em melhorar a acessibilidade do componente Accordion.
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
## Solução
|
||||
|
||||
Implementar um componente Accordion básico (não totalmente acessível) usando frameworks de UI é bastante simples devido ao fato de que apenas um valor de estado é necessário, os estados expandido/colapsado de cada seção. Os frameworks de UI também ajudam a manter o estado e a UI sincronizados, o que teríamos que implementar por conta própria se fôssemos usar Vanilla JavaScript.
|
||||
|
||||
### Props (Design da API)
|
||||
|
||||
Parte da complexidade da construção de um componente é projetar a API para ele. No caso de um framework baseado em componentes, estes seriam as propriedades do componente. No mínimo, precisaremos das seguintes props/atributos:
|
||||
|
||||
* `sections`: Uma lista de objetos de itens. Cada item é um objeto com os campos:
|
||||
* `value`: Um identificador único para o item do acordeão.
|
||||
* `title`: O rótulo de texto a ser exibido no título do acordeão.
|
||||
* `contents`: O conteúdo a ser exibido quando a seção é expandida.
|
||||
|
||||
### Estado
|
||||
|
||||
Podemos usar ES6 `Set` para acompanhar as seções que estão expandidas. Quando o título da seção é clicado, verifique se o valor da seção está dentro do conjunto. O valor será removido do conjunto se estiver dentro e adicionado ao conjunto caso contrário.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
## Casos de teste
|
||||
|
||||
* Todas as seções fornecidas devem ser exibidas.
|
||||
* Clicar no título de uma seção recolhida deve expandi-la.
|
||||
* Clicar no título de uma seção expandida deve recolhê-la.
|
||||
* Teste se todas as seções podem expandir e recolher independentemente.
|
||||
* Teste se você consegue inicializar várias instâncias do componente, cada uma com estados independentes.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 配置/API 设计
|
||||
|
||||
构建组件的复杂性部分在于设计其 API。`accordion` 函数接受一个根元素 `$rootEl`,在该元素中将插入手风琴部分。`accordion` 函数的第二个参数是一个用于存储配置选项的对象。 至少,我们需要以下选项:
|
||||
|
||||
* `items`:项目对象列表。 每个项目都是一个具有以下字段的对象:
|
||||
* `value`:手风琴项目的唯一标识符。
|
||||
* `title`:在手风琴标题中显示的文本标签。
|
||||
* `contents`:在展开该部分时显示的内容。
|
||||
|
||||
与我们典型的 Vanilla JS 方法不同,这次我们选择不在 JavaScript 中保留任何状态,而是依靠 DOM 来跟踪每个手风琴部分的状态,并根据该手风琴的状态展开/折叠相应的元素。
|
||||
|
||||
`accordion` 函数调用 `init` 和 `attachEvents` 函数,通过渲染 DOM 元素并附加必要的事件侦听器来设置手风琴组件。
|
||||
|
||||
### `init`
|
||||
|
||||
此函数设置在组件的整个生命周期中保留的 DOM 元素,也就是它们永远不会被销毁。 手风琴的各个部分(标题和内容)被渲染。
|
||||
|
||||
### `attachEvents`
|
||||
|
||||
此组件中只需要一个事件侦听器,即 `click` 事件,将其添加到根元素。 我们使用事件委托,以便只需要添加一个事件侦听器,并且它将适用于其所有子内容。 但是,我们必须小心检查单击了哪个元素,并确保仅在单击标题时才做出响应,而不是内容。
|
||||
|
||||
当在手风琴标题上触发单击时,我们需要旋转图标并在手风琴内容上切换 `hidden` 属性。
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import Description from '../../../index.mdx';
|
||||
|
||||
<Description />
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import TestCases from '../../../test-cases.mdx';
|
||||
import Notes from '../../../notes.mdx';
|
||||
import Solution from '../../../solution.mdx';
|
||||
|
||||
<Solution />
|
||||
|
||||
<TestCases />
|
||||
|
||||
<Notes />
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
title: 手风琴
|
||||
excerpt: 构建一个手风琴组件,该组件显示一个垂直堆叠的部分列表,每个部分包含一个标题和内容片段
|
||||
---
|
||||
|
||||
构建一个手风琴组件,该组件显示一个垂直堆叠的部分列表,每个部分包含一个标题和内容片段。 提供了部分 HTML 作为示例内容以及一个 chevron 图标。
|
||||
|
||||
## 要求
|
||||
|
||||
* 默认情况下,所有部分都折叠并且对视图隐藏。
|
||||
* 单击部分标题会切换内容。
|
||||
* 如果该部分已折叠,则该部分将展开,内容将显示。
|
||||
* 如果该部分已展开,则该部分将折叠,内容将被隐藏。
|
||||
* 这些部分彼此独立。
|
||||
|
||||
## 示例
|
||||
|
||||
试用[手风琴组件的示例](https://www.w3.org/WAI/ARIA/apg/example-index/accordion/accordion.html)。
|
||||
|
||||
## 笔记
|
||||
|
||||
* 此问题的重点是功能,而不是样式。 不要花太多时间编写自定义 CSS。
|
||||
* 您可以修改标记(例如,添加 `id`、数据属性、替换某些标签等)并使用客户端渲染。
|
||||
* 您可能需要考虑改进应用程序用户体验的方法并实施它们(在面试期间这样做可以获得额外加分)。
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
## 可访问性
|
||||
|
||||
交互元素需要可以聚焦,所以我们将使用`<button>`作为标题。
|
||||
|
||||
The [ARIA Authoring Practices Guide for Accordion](https://www.w3.org/WAI/ARIA/apg/patterns/accordion) 有一个关于 ARIA 角色、状态和属性的指南,需要添加到手风琴的各种元素中。[Accordion II](/questions/user-interface/accordion-ii) 和 [Accordion III](/questions/user-interface/accordion-iii) 将侧重于改进 Accordion 组件的可访问性。
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
## 解决方案
|
||||
|
||||
由于只需要一个状态值,即每个部分的展开/折叠状态,因此使用 UI 框架实现一个基本的(非完全可访问的)Accordion 组件非常简单。UI 框架也有助于保持状态和 UI 的同步,如果使用 Vanilla JavaScript,我们将不得不自己实现这一点。
|
||||
|
||||
### Props(API 设计)
|
||||
|
||||
构建组件的复杂性部分在于设计其 API。对于基于组件的框架,这将是组件的属性。至少,我们需要以下 props/attributes:
|
||||
|
||||
* `sections`:项目对象列表。每个项目都是一个具有以下字段的对象:
|
||||
* `value`:手风琴项目的唯一标识符。
|
||||
* `title`:在手风琴标题中显示的文本标签。
|
||||
* `contents`:展开该部分时显示的内容。
|
||||
|
||||
### 状态
|
||||
|
||||
我们可以使用 ES6 `Set` 来跟踪已展开的部分。当单击部分标题时,检查该部分的值是否在集合中。如果该值在集合中,则将其从集合中删除,否则将其添加到集合中。
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
## 测试用例
|
||||
|
||||
* 应该显示所有提供的部分。
|
||||
* 点击折叠部分标题应该展开它。
|
||||
* 点击展开部分标题应该折叠它。
|
||||
* 测试所有部分是否允许独立展开和折叠。
|
||||
* 测试您是否能够初始化该组件的多个实例,每个实例都具有独立的状态。
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "langnostic",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"description": "Modern translation toolchain using AI",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
|
|
|||
Loading…
Reference in New Issue