An open API service indexing awesome lists of open source software.

https://github.com/jackchoumine/advanced-vue-component-design-demos

vue 高级组件设计 demos
https://github.com/jackchoumine/advanced-vue-component-design-demos

vue3-composition-api vue3-demo

Last synced: 2 months ago
JSON representation

vue 高级组件设计 demos

Awesome Lists containing this project

README

        

# advanced-vue-component-design 之受控组件

总结实用(项目里能马上用到的)的 vue 组件设计方法,让封装组件更加容易,代码更加好维护。

> [demos 预览](https://jackchoumine.github.io/advanced-vue-component-design-demos/)

## 受控组件 controlled component

受控组件:组件的状态完全由 vue 控制的组件。vue 和 react 中的受控组件和非受控组件的概念是一样的。

[vue 关于表单组件的详细介绍](https://vuejs.org/guide/essentials/forms.html)

[react 的受控组件](https://zh-hans.reactjs.org/docs/forms.html#controlled-components)

常见的表 input、select 等表单元素带有 value 属性,具有自己的状态,如果这些状态由 vue 控制,就就变受控组件。

vue 通过`v-model`来实现受控组件,自定义组件上使用 v-model 非常容易。

比如`MyInput`组件,vue3 中可这样使用。

```html

```

MyInput 的实现:

```html


title



content



import { ref, reactive, watch, computed, defineComponent } from 'vue'
export default defineComponent({
name: 'MyInput',
props: ['modelValue', 'title'],
setup(props, { emit, attrs, slots }) {
// console.log(props.title)
function onInput(event) {
emit('update:modelValue', event.target.value)
}
function onInputTitle(event) {
emit('update:title', event.target.value)
}
return { onInputTitle, onInput }
},
})

```

v-model 指令的原理:modelValue 绑定到 value 上和在 input 事件中触发`update:modelValue`自定义事件。

> 如何修改 prop 的名字和自定义事件呢?

`v-model:propName + update:propName`

默认情况下,v-model 不需要指定参数,修改 prop 的名字后,需要指定参数,比如上面的`v-mode:title`。vue3 加强了 v-model,可实现传递多个值,比如上面的 ``。

## 如何使用受控组件实现一个类似微信的 switch 组件?

![](https://tva1.sinaimg.cn/large/e6c9d24egy1h4b8zda7bhj203y02iwea.jpg)

先看使用方式:

```html

```

直接上代码:

```html

import { ref, reactive, watch, computed, defineComponent } from 'vue'
export default defineComponent({
name: 'ToggleInput',
props: ['modelValue'],
setup(props, { emit, attrs, slots }) {
function toggle() {
console.log('点击', props.modelValue)
emit('update:modelValue', !props.modelValue)
}
return { toggle }
},
})

$border-radius: 9999px;
$toggle-width: 3rem;
$toggle-height: 1.5rem;

.toggle {
/* background-color: red; */
position: relative;
display: inline-block;
height: $toggle-height;
width: $toggle-width;

flex-shrink: 0;
border-radius: $border-radius;
cursor: pointer;

/* 聚焦时样式 */
&:focus {
outline: 0;
box-shadow: 0 0 0 2px rgba(52, 144, 220, 0.5);
}

&:before {
display: inline-block;
border-radius: $border-radius;
height: 100%;
width: 100%;
content: '';
background-color: #dae1e7;
/* background-color: red; */
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
transition: background-color 0.2s ease;
}
/* 开启后背景颜色变为绿色 */
&[aria-checked='true']:before {
background-color: #04be02;
}

/* 移动的按钮,关闭时位于左侧,left:0 */
&:after {
position: absolute;
top: 0;
left: 0;

height: $toggle-height;
width: $toggle-height;
background-color: #fff;

border-radius: $border-radius;
border-width: 1px;
border-color: #dae1e7;

box-shadow: 0 2px 4px 0 rgb(0 0 0 / 10%);
content: '';

transform: translateX(0);
transition: transform 0.2s ease;
}

/* 开启后,向右移动 0.5 的 span 宽度 */
&[aria-checked='true']:after {
transform: translateX(#{$toggle-height});
}
}

```

> tabindex="0" 的作用是什么?

元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素。

> role="checkbox" 的作用是什么?

告诉屏幕阅读器,这是多选框。

> aria-checked 的作用是什么?

告诉屏幕阅读器,元素选中状态。ARIA (Accessible Rich Internet Applications) 是一组属性,用于定义使残障人士更容易访问 Web 内容和 Web 应用程序。

role、aria-\* 都是为了实现无障碍访问添加的属性

实现的关键点:

1. 使用绝对定位放置圆形按钮,且使用伪元素。

2. 当状态改变时,移动元素按钮,同时改变组件的背景色。

## 再思考 v-model 的使用

在原生标签上

```html

```

自定义在组件上

```html

```

组件实现`v-model`:声明`model-value`的 prop, 将该 prop 绑定到 value 上,在 value 改变时,通过自定义事件 `update:modelValue` 把最新的值抛出。

```js
app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `

`,
})
```

v-model 在自定义组件上使用:

```html

```

## v-model 如何是计算属性结合使用?

> 在 set 中触发自定义事件。

```js
app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `

`,
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
},
},
},
})
```

> 这种实现在二次封装表单组件时,特别有用。

> 什么时候使用`modelValue`+`update:modelValue`代替 v-model?

组件在循环中时,比如下面的例子。

```html





```