@@ -132,6 +132,159 @@ input输入框上的 `v-model` 只是一个简化的指令,它的双向绑定
132
132
133
133
## ` v-model ` 在自定义组件中的使用
134
134
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
+
135
288
136
289
137
290
0 commit comments