当前端某个页面代码过多的时候,我们可以把代码拆分,做为自定义组件来引用,这样不至于代码过于繁杂,清晰易懂。
一、语法:
把拆分的代码单独放到某个vue文件中做为子组件,这个子组件中就是普通的vue代码,可以放在components目录下,也可以放在views目录下(放在views下,不需要在router中声明路径),还可以放在其他自定义目录中。父组件调用子组件的步骤:
1、使用import引入子组件并在components中声明这个子组件:
<script>
//your-child-file-name为子组件文件名,YourChildFileName为别名(可以和文件名一样)
import YourChildFileName from './children/your-child-file-name';
export default {
components: {
YourChildFileName,
......
}
}
</script>
2、使用定义的子组件做为标签使用:
<template>
<div>
<YourChildFileName></YourChildFileName>
</div>
</template>
二、父子组件通信:
1、父组件传值给子组件:(1)父组件使用v-bind传递,值可加引号也可以不加,如 v-bind:formDataList="formDataList"和 v-bind:formDataList=formDataList都可以,也可以直接去掉v-bind,表示使用this.可以拿到的数据,如果是直接定义的字符串等常量则不需要使用前面的冒号,如这里的idColumn、nameColumn;
<SelectItem
v-for="(item, index) in userArea.cityIds"
:key="index"
:id="item"
:dataList="cityList"
idColumn="cityId"
nameColumn="cityName"
@deleteId="deleteId"
>
</SelectItem>
(2)子组件接收:使用props接收父组件的传值,使用时相当于data里面的数据,可以使用this.来获取。如:
父组件:把formDataList传给子组件:
<flow-node v-for="(item, index) in nodeData" :key="index" :index="index" :node="item"
v-bind:formDataList="formDataList"
@draggableEvent="updateDraggable">
</flow-node>
<script>
import updateNode from '../../components/flow/updateNode'
export default {
data() {
return {
formDataList: []
}
},
components: {
'flow-node': updateNode
}
}
</script>
子组件:updateNode.vue:
export default {
name: 'updateNode',
data() {
return {
}
},
props: {
formDataList: {
required: true,
type: Array
}
},
}
}
2、子组件调用父组件的方法:实现子数据传输给父,子组件通过emit传递调用父组件函数,其中,父组件函数名后不要加()。如: 子:
<el-col :span="10">
<el-select v-model="dataType" @change="onMappingChange">
<el-option v-for="(item, index) in dataTypes" :label="item" :value="item" :key="index"></el-option>
</el-select>
</el-col>
methods: {
onMappingChange() {
var _this = this
this.$emit('mappingChange', {
index: _this.itemIndex,
action: 'change',
mapping: {
name: _this.name,
dataType: _this.dataType
}
})
},
onDeleteMapping() {
var _this = this
this.$emit('mappingChange', {
index: _this.itemIndex,
action: 'delete'
})
}
}
父:在调用处声明方法:
<vue-mapping v-for="(item, index) in fieldMetas" :key="index" :item-index="index" :item-mapping="item" @mappingChange="fieldMetaChange"></vue-mapping>
fieldMetaChange(val) {
if (val.action === 'change') {
this.fieldMetas.splice(val.index, 1, val.mapping)
} else if (val.action === 'delete') {
this.fieldMetas.splice(val.index, 1)
}
},
3、父组件调用子组件的方法:使用$refs。如: 子:
<!-- @format -->
<template>
</template>
<script>
export default {
methods: {
loadData() {
alert("我是子组件的方法");
}
},
};
</script>
父:
<el-table name="0" label="用户">
<PersonIn ref="personIn"></PersonIn>
</el-table>
<script>
import PersonIn from './children/person-in';
methods:{
searchHandler() {
if (this.activeName === '0') {
this.$refs.personIn.loadData();
}
}
</script>
三、父组件循环调用子组件:
v-for有两种写法,写在外面和里面都可以,如以下两种写法效果是一样的:
<div v-for="(item, index) in mongoFieldMetas " :key="index"> <mongo-vue-mapping
:item-index="index"
:item-mapping="item"
@mappingChange="mongoFieldMetaChange"
></mongo-vue-mapping></div>
<mongo-vue-mapping
v-for="(item, index) in mongoFieldMetas"
:key="index"
:item-index="index"
:item-mapping="item"
@mappingChange="mongoFieldMetaChange"
></mongo-vue-mapping>
综合举例:
1、例1:子组件为一个下拉框公用组件,接收父组件传递的下拉框列表、输入框初始值,并把改变后的值返回给父组件。
(1)、router:
{
path: '/parent',
redirct: '/test/parent',
name: 'test',
component: Layout,
meta: { title: 'parent', authority: ['role_manage'] },
noDropdown: true,
children: [
{
path: 'parent',
name: 'parent',
component: () => import('@/views/test/parent'),
meta: { title: 'parent', authority: ['role_manage'], keepAlive: false }
}
]
}
(2)、parent.vue:
<template>
<div>
<span> 我是parent,select:{{selectValue}},input:{{name}}</span>
<select-child v-bind:list = list v-bind:name=name @slectChange = "parentGetSelectValues"
@changeInput = 'parentGetInput'></select-child>
</div>
</template>
<script>
import child from './child'
export default {
data () {
return {
list:['c1','c2','c3','c4','c5','c6'],
selectValue:'',
name:'parent'
}
},
methods: {
parentGetSelectValues(val){
this.selectValue = val.data;
alert('parent'+this.selectValue)
},
parentGetInput(val){
this.name = val.data
}
},
components: {
'select-child':child
}
}
</script>
<style scoped>
</style>
(3)、组件child.vue:
<template>
<div>
<span>我是child</span>
<el-input v-model="name" @blur="inputChange()"></el-input>
<el-select v-model="val" placeholder="请选择" @change="childChange()">
<el-option v-for="item in list" :key="item" :label="item" :value="item"></el-option>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
val: ""
};
},
props: {
list: {
required: true,
type: Array
},
name: {
required: true,
type: String
}
},
methods: {
childChange() {
alert("child" + this.val);
this.$emit("slectChange", {
data: this.val
});
},
inputChange(){
this.$emit("changeInput", {
data:this.name
});
}
}
};
</script>
<style scoped>
</style>
访问http://localhost:9528/#/parent/parent:
选择一个值,弹框两次 ,
2、例2:动态新增映射:如页面初始化有两个值,可以点击+号新增项,也能点击-号删除项:
(1)index.vue:为父页面:
<template>
<div>
<div class="btn-add-mapping">
<el-button @click="addMongoMapping">+</el-button>
</div>
<mongo-vue-mapping
v-for="(item, index) in mongoFieldMetas"
:key="index"
:item-index="index"
:item-mapping="item"
@mappingChange="mongoFieldMetaChange"
></mongo-vue-mapping>
<div><el-button @click="submit()" type="primary">提交</el-button></div>
</div>
</template>
<script>
import MongoMapping from "../../components/common/mongomapping";
export default {
data () {
return {
mongoFieldMetas:[{"name":"初始值name1","path":"path1","type":"String"},{"name":"初始值name2","path":"path2","type":"Date"}]
}
},
components: {
'mongo-vue-mapping': MongoMapping,
},
methods: {
//新增
addMongoMapping() {
this.mongoFieldMetas.push({})
},
//
mongoFieldMetaChange(val) {
if (val.action === 'change') {
this.mongoFieldMetas.splice(val.index, 1, val.mapping)
} else if (val.action === 'delete') {
this.mongoFieldMetas.splice(val.index, 1)
}
},
//提交
submit(){
alert(JSON.stringify(this.mongoFieldMetas))
}
}
};
</script>
<style scoped>
</style>
(2)mongomapping.vue为子组件:
<template>
<el-row>
<el-col :span="7">
<el-input v-model="name" @change="onMappingChange" placeholder="字段名"></el-input>
</el-col>
<el-col :span="7">
<el-input v-model="path" @change="onMappingChange" placeholder="path"></el-input>
</el-col>
<el-col :span="7">
<el-select v-model="type" @change="onMappingChange">
<el-option v-for="(item, index) in dataTypes" :label="item" :value="item" :key="index"></el-option>
</el-select>
</el-col>
<el-col :span="2">
<el-button @click="onDeleteMapping">x</el-button>
</el-col>
</el-row>
</template>
<script>
export default {
name: 'mongomapping',
data() {
return {
dataTypes: [
'Integer', 'String', 'Boolean', 'Date'
],
name: '',
path: '',
type: ''
}
},
props: {
itemIndex: {
required: true,
type: Number
},
itemMapping: {
required: true,
type: Object
}
},
created() {
this.name = this.itemMapping.name || ''
this.path = this.itemMapping.path || ''
this.type = this.itemMapping.type || ''
},
watch: {
itemMapping() {
this.name = this.itemMapping.name || ''
this.path = this.itemMapping.path || ''
this.type = this.itemMapping.type || ''
}
},
methods: {
onMappingChange() {
var _this = this
this.$emit('mappingChange', {
index: _this.itemIndex,
action: 'change',
mapping: {
name: _this.name,
path: _this.path,
type: _this.type
}
})
},
onDeleteMapping() {
var _this = this
this.$emit('mappingChange', {
index: _this.itemIndex,
action: 'delete'
})
}
}
}
</script>
<style scoped>
</style>
再如:
<template>
<div>
<!--用户区-->
<div v-for="(item,index) in users" :key="index">
<addUser :index="index" :user="item" @userChange="updateUser"></addUser>
</div>
<el-button @click="addUser()">+</el-button>
<div>
<el-button @click="submit()">提交</el-button>
</div>
</div>
</template>
<script>
import addUser from "../../components/common/addUser";
export default {
data() {
return {
users: [{ name: "张三", age: 19 }]
};
},
components: { addUser: addUser },
methods: {
addUser() {
this.users.push({});
},
updateUser(param) {
var index = param.index;
var user = param.user;
if (param.type === 'update') {
this.users.splice( index,1, user);
} else if (param.type === 'delete') {
this.users.splice( index,1);
}
},
submit() {
alert(JSON.stringify(this.users));
}
}
};
</script>
<style scoped>
</style>
<template>
<div>
<el-row>
<el-col :span="6">
<el-input placeholder="姓名" v-model="user.name" @change="change('update')"></el-input>
</el-col>
<el-col :span="6">
<el-input placeholder="年龄" v-model="user.age" @change="change('update')"></el-input>
</el-col>
<el-col :span="2">
<el-button @click="change('delete')">-</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
props: {
index: { required: true, type: Number },
user: { required: true, type: Object }
},
methods: {
change(val) {
let param = {};
param.type = val;
param.index = this.index;
param.user = this.user;
this.$emit("userChange", param);
}
}
};
</script>
<style scoped>
</style>