Skip to content

Commit 141a989

Browse files
committed
complete v-model article 🐼 🐞 🐙
1 parent 54b4946 commit 141a989

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

Blog/65.从 Vue.js 自定义输入框深入理解 v-model.md

+153
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,159 @@ input输入框上的 `v-model` 只是一个简化的指令,它的双向绑定
132132

133133
## `v-model` 在自定义组件中的使用
134134

135+
自定义组件中也可以使用 `v-model`
136+
137+
```html
138+
<custom-component v-model="custom" />
139+
```
140+
141+
和这种用法是一样的:
142+
143+
```html
144+
<custom-component :value="custom" @input="val => custom = val" />
145+
```
146+
147+
在 2.2.0+ 的版本中可以使用 `model` 属性在自定义组件中来实现属性和事件的自定义:
148+
149+
```js
150+
export default {
151+
name: 'custom-component',
152+
model: {
153+
prop: 'customVal',
154+
event: 'customEvent'
155+
}
156+
}
157+
```
158+
159+
`v-model` 将会查询所有的属性来替代 `value` 属性,并使用 `prop` 中来替代 `input` 事件的监听。
160+
因此上面的那个 `custom-component` 组件被改写为
161+
162+
```html
163+
<custom-component :customVal="custom" @customEvent="val => custom = val" />
164+
```
165+
166+
### 自定义 `radio` 按钮中使用 `v-model`
167+
168+
`label` 标签来做模拟一个简单的实现:
169+
170+
```html
171+
<template>
172+
<label>
173+
<input type="radio" :checked="checkVal" :value="value" @change="update">
174+
{{ label }}
175+
</label>
176+
</template>
177+
<script>
178+
export default {
179+
model: {
180+
prop: 'modelVal',
181+
event: 'change'
182+
},
183+
props: {
184+
value: {
185+
type: String,
186+
},
187+
modelVal: {
188+
default: ""
189+
},
190+
label: {
191+
type: String,
192+
required: true
193+
},
194+
},
195+
computed: {
196+
checkVal() {
197+
return this.modelVal == this.value
198+
}
199+
},
200+
methods: {
201+
update() {
202+
this.$emit('change', this.value)
203+
}
204+
}
205+
}
206+
</script>
207+
```
208+
209+
这里只是做模拟所以 `props` 中只写了这里能用到的属性
210+
211+
### 自定义 `checkbox` 按钮中使用 `v-model`
212+
213+
因为要支持单个 `true false` 类型的 `checkbox`(同时支持 `true-value` `false-value`)和多个 `checkbox`,将所有选中的值存入数组中。因此这里的代码就稍微复杂了一些。
214+
215+
其实只要把上面 `checkbox` `v-model` 代码的实现再增加些判断逻辑就能实现:
216+
217+
```html
218+
<template>
219+
<label>
220+
<input type="checkbox" :checked="checkVal" :value="value" @change="update">
221+
{{ label }}
222+
</label>
223+
</template>
224+
<script>
225+
export default {
226+
model: {
227+
prop: 'modelVal',
228+
event: 'change'
229+
},
230+
props: {
231+
value: {
232+
type: String,
233+
},
234+
modelVal: {
235+
default: false
236+
},
237+
label: {
238+
type: String,
239+
required: true
240+
},
241+
// 定义 true-value false-value
242+
trueValue: {
243+
default: true
244+
},
245+
falseValue: {
246+
default: false
247+
}
248+
},
249+
computed: {
250+
checkVal() {
251+
// 判断是一个还是多个 checkbox
252+
if (this.modelVal instanceof Array) {
253+
return this.modelVal.includes(this.value)
254+
}
255+
return this.modelVal === this.trueValue
256+
}
257+
},
258+
methods: {
259+
update(event) {
260+
const isChecked = event.target.checked
261+
// 这里也要判断是一个还是多个 checkbox
262+
if (this.modelVal instanceof Array) {
263+
const newVal = [...this.modelVal]
264+
if (isChecked) {
265+
newVal.push(this.value)
266+
} else {
267+
newVal.splice(newVal.indexOf(this.value), 1)
268+
}
269+
this.$emit('change', newVal)
270+
} else {
271+
this.$emit('change', isChecked ? this.trueValue : this.falseValue)
272+
}
273+
}
274+
}
275+
}
276+
</script>
277+
```
278+
279+
上面自定义的组件代码也不是很复杂,只是为了通过代码解释下 `v-model` 在内部是如何工作的,所以功能肯定不完整。
280+
281+
## 最后
282+
283+
vue.js 官方以提供了很多优秀的[第三方组件库](https://github.com/vuejs/awesome-vue#frameworks),自定义组件的实现原理其实也大同小异。
284+
285+
286+
287+
135288

136289

137290

0 commit comments

Comments
 (0)