Vue 组件组合:计算器 + 转换器
需求分析:
来看自带计算器的构成,计算器(左) 菜单(中) 转换器(右):
我的构思是:
- 计算器-数值 和 计算器-单位 分别作为一个单文件组件,包含它俩的父组件名为 计算器。
- 菜单在父组件中。
- 父组件通过调整菜单,来控制两个子组件的切换。
组件内容:
App.vue
调用
<template> <div> <calculator :cal-num-options="{'basic':true, 'science':false, 'programmer':false}" :cal-unit-options="true"> </calculator> <!--计算器--> </div> </template> <script> import Calculator from './Calculator.vue' //导入组件 export default{ components:{Calculator} //注册组件 } </script>
Calculator.vue
父组件
<template> <div id="calculator"> <select v-model="menu" >...</select> <!--菜单--> <cal-num :menu="menu"> </cal-num> <!--计算器-数值--> <cal-unit :menu="menu"> </cal-unit> <!--计算器-单位--> </div> </template>
<script> import CalNum from './CalNum.vue' //导入组件 import CalUnit from './CalUnit.vue' export default{ props: { //接受外部参数 'calNumOptions':{ type: Object, default: {'basic':true, 'science':false, 'programmer': false} }, 'calUnitOptions':{ type: Boolean, default: false } }, data (){ //自身数据(将要传给子组件) return{ menu: 'basic' }; }, components:{ //注册组件 CalNum, CalUnit } } </script>
CalUnit.vue
内容
<template> <div> ... <!----选择列表1----> <select @change="selectChange($event,0)"> <option v-for="item in units[menu]" :value="item.ref"> {{item.text}} </option> <!--根据菜单显示列表内容--> </select> ... </div> </template>
<script> export default{ props:{ menu: String //接受菜单参数 }, data (){ return { ... units:{ //单位 volume:[ {text:'毫升', ref:1}, {text:'升', ref:1000}, ... ] } } } ... } </script>
自检:是否符合开发规范
构成组件
- props —— 见上图。
- events —— 子组件没有事件要发给父组件的,故忽略之。
- slots —— 父组件没有内容需要传到子组件的,故忽略之。理解slot 概念
组件间通信
- 使用 props
业务无关
- 命名只表达组件功能
- 业务数据无关
- 对外部无依赖
命名空间
- 命名空间
cal-
上下文无关
- 没有特别需求且单个组件不至于过重的的前提下,不把一个有独立功能的组件
cal-num
cal-unit
拆分成若干个小组件
数据扁平化(不符合)
calUnitOptions
类型为Boolean
,calNumOptions
类型为Object
使用自定义事件实现数据的双向绑定(不需要)
使用自定义 watcher 优化 DOM 操作
cal-unit
中的 watcher:menu
项目骨架(见上图)
踩坑小记:
<select>
标签绑定数组的元素时,若选项的value
值相同,则不会触发绑定的数组的改变。
- 示例代码:
<div id="app"> <select v-model="myval[0]"> <option v-for="option in options" :value="option.value">{{option.text}}</option> </select> myval is: {{myval}} </div> </template>
<script> export default{ data (){ return { myval:['', ''], options: [ {text: 'A', value: '1'}, {text: 'B', value: '1'}, {text: 'C', value: '3'} ] } } } </script>
- 解决:手动在
<select>
标签上绑定change()
方法,修改数组元素的值
小知识点
import Calculator from './Calculator.vue'
,其中./
表示当前路径下,不加的话找不到的- export default 和 new vue
- Vue 中对于命名的调整:驼峰式命名与短横线隔开式命名
- 复用子组件时,加载了两个样式表(父和子),并且有冲突。解决:
<style>
标签要加上scoped
属性,会把样式作用域限制在当前组件内。