vue使用感受(一)组件间传值
从上周开始,我开始接触了vue等前端框架,在此做一些总结,说说自己的感受。手头这个项目是PC端的一个管理系统。之前的开发中并没有使用前端框架,而是在一个流程引擎的基础上进行开发的。每一个流程都有许多表单,这些表单是由引擎自动渲染产生的,并没有html或jsp文件。如果要修改表单样式,需要每个表单对应一个js文件,在js文件中进行样式的修改。这个操作很傻,但是大佬们都表示没有办法。几百个表单,改到炸裂= =。
最近又提出要把现有的这个系统做一个移动端。原先的PC端系统是比较复杂的,直接做移动端适配肯定是不行的。所以一个想法就是借助前端框架来简化我这边的工作。我之前是久闻vue的大名,但是一直没有着手尝试过。于是我总共花了一周把项目样子搭出来了。然而后端大佬表示表单这部分还是不能提供接口,我表示很心塞。(我现在就在考虑如何让自己不改那几百个js)
话说回来,虽然表单这部分帮不上,vue在项目的其他部分是帮我简化了很多工作的。首先组件化这个我就很喜欢。因为我之前有做过一段时间的安卓开发,这种界面上分各个组件,组件复用等等很和我的胃口。其次,每一个vue中包含的template,script,style三部分,可以把项目中很多内容分隔开,不会互相产生影响。我不用建很多css文件和js文件,每个组件都十分独立(耦合度低?)。
前言
在这个项目中,我用了iView这个UI组件库,还是很方便的。推荐大家直接从iView的推荐工程开始入手,免去自己配置和调试。
https://github.com/iview/iview-project
接下来,我整理一下自己这一周遇到的一些问题以及我是如何解决的,希望有大佬能给点建议:
- 组件间传值
- 父组件向子组件
- 子组件向父组件
- 子组件间
- 组件间跳转
- vue-router
- 如何路由不变,部分组件跳转
- 样式覆盖
- 与后台接口交互
上面这些问题,基本上都可以百度找到答案。我就结合我自己实际的例子把它们汇总一下。至于现在还有什么问题没解决,就是那几百个表单了。由于篇幅原因,我把上面四个问题分为三次来聊。这次主要说说组件间的传值。 组件间传值
这个是遇到的第一个问题,而且你在项目的各个地方都有可能遇到。这边我就用我做的一个测试系统来解释一下。
我们先来看这个待办页面,它就包含了子组件向父组件、父组件向子组件两种传值。
父组件向子组件传值
我们可以把这个页面分成三部分:Header、Content、Footer。当然我这边还有一个侧边栏,暂时没它的事情就不提了。
Header和Footer在大多数界面都是不变的,主要在变化的就是Content。那么Content这部分我们可以做一个大组件。比如说待办这个页面的Content就是Todo.vue这个大组件。
在这个大组件中,我们又可以划分一些小组件。小组件的划分并不是必要的,也不用很细。我们只要考虑那些组件是我们在其他界面上可以复用的就行。比如说这里我只划分出一个自定义组件。
当然,这里用到很多iView的组件,比如说Form、Input、Card。自定义组件CustomListItem需要3个参数:标题、来源和日期。而这些参数我们需要通过Todo.vue这个父组件向后台接口请求数据之后,在一一添加给CustomListItem这个子组件。也就是父组件向子组件传值。这边我没有放入后台请求的部分,就只关注传值。
首先,是CustomListItem组件。
<template>
<div class="listItem">
<Row>
<Col span="4">
<Avatar icon="ios-paw" size="large"></Avatar>
</Col>
<Col span="20">
<h3>{{title}}</h3>
<div style="width:100%;">
<p style="display:inline-block;">{{lastUser}}</p>
<p style="display:inline-block;float:right;">{{time}}</p>
</div>
</Col>
</Row>
<hr style="margin:5px 0;">
</div>
</template>
<style scoped>
.item-inline{
display: inline-block;
}
.listItem{
background: #fff;
}
</style>
<script>
export default {
data () {
return {}
},
props: ['title', 'lastUser', 'time']
}
</script>
我们把参数定义在props中,并在template中引用。接下来就是父组件Todo.vue。
<template>
<div class="todo">
<Form :model="searchForm" inline>
<FormItem style="width:100%; padding:10px;margin:0;">
<Input v-model="searchForm.input" icon="search" placeholder="请输入标题关键字" />
</FormItem>
</Form>
<hr>
<div style="overflow:auto;height:480px;">
<div style="margin-bottom:10px;">
<div class="listItemTitle">审片</div>
<Card style="width:100%;" :bordered="false">
<div @click="toDetail">
<CustomListItem :title="itemTitle" :lastUser="itemLastUser" :time="itemTime"></CustomListItem>
</div>
</Card>
</div>
</div>
</div>
</template>
<script>
import CustomListItem from '../children/CustomListItem'
export default {
data () {
return {
title: '待办',
searchForm: {
input: ''
},
itemTitle: '流程标题',
itemLastUser: '上级来源',
itemTime: '日期时间'
}
},
created() {
this.$emit('setTitle', this.title)
},
components: {
CustomListItem
},
methods: {
toDetail () {
//跳转到具体流程表单页面
this.$router.push({
name: 'detail'
})
}
}
}
</script>
<style scoped>
.todo{
background: #f5f7f9;
overflow: auto;
}
</style>
这里的Todo.vue的data中定义了三个值itemTitle、itemLastUser、itemTime分别动态的和CustomListItem中的title、lastUser和time绑定。这样我们就可以把Todo.vue中的值传递过去了。
子组件向父组件传值
我们回到那个有Header、Content和Footer的界面。
Header这边主要有两个部分:按钮和标题。在这里这个标题是待办,但是在主页或者其他界面,应该要显示当前Content的标题。所以我们需要从Content这部分的组件向包含Header的这个父组件传值。也就是子组件向父组件传值。
首先是子组件还是刚才的Todo.vue。我们在created这个生命周期函数中使用了this.$emit()方法,向setTitle这个方法传递了title这个参数。
<template>
<div class="todo">
<Form :model="searchForm" inline>
<FormItem style="width:100%; padding:10px;margin:0;">
<Input v-model="searchForm.input" icon="search" placeholder="请输入标题关键字" />
</FormItem>
</Form>
<hr>
<div style="overflow:auto;height:480px;">
<div style="margin-bottom:10px;">
<div class="listItemTitle">审片</div>
<Card style="width:100%;" :bordered="false">
<div @click="toDetail">
<CustomListItem :title="itemTitle" :lastUser="itemLastUser" :time="itemTime"></CustomListItem>
</div>
</Card>
</div>
</div>
</div>
</template>
<script>
import CustomListItem from '../children/CustomListItem'
export default {
data () {
return {
title: '待办',
searchForm: {
input: ''
},
itemTitle: '流程标题',
itemLastUser: '上级来源',
itemTime: '日期时间'
}
},
created() {
this.$emit('setTitle', this.title)
},
components: {
CustomListItem
},
methods: {
toDetail () {
//跳转到具体流程表单页面
this.$router.push({
name: 'detail'
})
}
}
}
</script>
<style scoped>
.todo{
background: #f5f7f9;
overflow: auto;
}
</style>
然后我们在父组件中用setHeader方法接收一下这个setTitle。(这个文件我删了很多方法,直接复制应该是跑不起来的)
<template>
<div class="layout first">
<Layout :style="{height: '100%'}">
<Header :style="{padding: 0}" class="layout-header-bar">
<Icon @click.native="collapsedSider" :class="rotateIcon" :style="{margin: '20px 20px 0'}" type="navicon-round" size="24"></Icon>
<h2 style="display:inline-block">{{title}}</h2>
</Header>
<Content style="background:#f5f7f9;minHeight:260px;position:absolute;width:100%;top:64px;">
<component v-bind:is="tabView" @setTitle="setHeader" @setPageByMain="setPageByMainPage"></component>
</Content>
<Footer style="position:absolute;bottom:0;width:100%;padding:0;background:#fff;">
<BottomMenu style="height: 60px;" @setPageByMain="setPageByMainPage"></BottomMenu>
</Footer>
</Layout>
</div>
</template>
<script>
import MainPage from './children/MainPage'
import BottomMenu from './children/BottomMenu'
import Todo from './menuPage/Todo'
export default {
name: 'first',
data () {
return {
tabView: 'MainPage',
title: '',
}
},
methods: {
setHeader (data) {
this.title = data
}
},
components: {
UserInfo,
MainPage,
BottomMenu,
Todo
}
}
</script>
至于这里的component组件我们会在之后的组件间跳转中提到。
子组件向子组件传值
子组件间传值需要通过一个类似于事件总线的东西来作为媒介。这个用到的地方比较少,就举个简单的例子。首先我们在src路径下创建一个bus.js的文件(文件名可以随便取。路径保证在src下级即可)。
import Vue from 'vue'
export default new Vue;
然后我们在子组件中引入bus.js,并在要传值的方法中通过bus来触发自定义的事件。
<template>
<div class="msg">
<label>
<span>请输入值(子组件):</span>
<input v-model="msg" />
</label>
<div id="emit">
<Button type="primary" @click="bus">把值传递给另一个子组件</Button>
</div>
</div>
</template>
<script>
import Bus from '../bus.js'
export default {
data () {
return {
msg: ''
}
},
methods: {
bus: function () {
Bus.$emit('getFromBus', this.msg)
console.log("child2触发了getFromBus")
}
}
}
</script>
然后在另一个子组件中接收。
<template>
<div class="header">
<div id="on">
<h1>{{message}}</h1>
</div>
</div>
</template>
<script>
import Bus from '../bus.js'
export default {
data () {
return {
message: ''
}
},
created() {
Bus.$on('getFromBus', (msg) => {
console.log("child接收到了getFromBus")
this.message = msg
})
}
}
</script>
以上就是vue组件间传值啦~后面还会聊一聊组件间跳转以及其他遇到的一些问题,敬请关注~