利用async/await 关键字,咱们能够优雅的处理异步逻辑。css
好比调用网络接口能够直接await fetch(……)vue
事实上,在处理页面交互逻辑时使用async/await,也能够起到很好的解耦做用,写出更清晰的代码。react
好比获取Modal弹框的交互结果:git
直接看效果: DEMO on githubgithub
后台系统在交互设计上常常使用模态弹框。不少UI框架都提供了方便易用的Modal组件,好比Ant design: Antd Modalweb
import { Modal, Button } from 'antd';
class App extends React.Component {
state = { visible: false } // 仍是须要维护一个visible state用来控制Modal的显示状态
showModal = () => {
this.setState({
visible: true,
});
}
handleOk = (e) => {
this.setState({
visible: false,
});
}
handleCancel = (e) => {
this.setState({
visible: false,
});
}
render() {
return (
<div> <Button type="primary" onClick={this.showModal}> Open Modal </Button> <Modal title="Basic Modal" visible={this.state.visible} onOk={this.handleOk} onCancel={this.handleCancel} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> </div>
);
}
}
ReactDOM.render(<App />, mountNode); 复制代码
以上代码能够看出:受制于React一般的写法,在频繁使用Modal的场景下Antd的封装使用起来仍是有些繁琐element-ui
固然,做为中后台系统的优秀解决方案,Antd的小伙伴帮咱们封装了Modal.methods能够快速的建立一些简易的弹窗:bash
Modal.confirm({
title: 'Confirm',
content: 'Bla bla ...',
okText: '确认',
cancelText: '取消',
});
复制代码
这是一个不错的思路,可是Antd官方提供的methods功能很是有限。网络
但愿可以实现result = await Modal.open()
这样的调用方式。antd
一种思路是在实现一个Modal class,上面有static open这样一个方法,当调用open时,向页面插入一个modal,相似上面Modal.confirm的作法。
另外一种办法,能够先在页面实例化一个modal,须要open的时候利用ref attribute获取到已经实例化的modal,并调用它的open 方法。 以下:
import React from 'react';
import { Modal, Input } from 'antd';
export default class AsyncModalDemo extends React.Component {
state = {
visible: false,
text: ''
}
open = () => {
this.setState({
visible: true,
});
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
close = () => {
this.setState({
visible: false,
});
if (this.reject && typeof this.reject === 'function') {
this.reject('cancel');
}
}
handleOk = () => {
if (typeof this.resolve === 'function') {
this.resolve(this.state.text);
}
delete this.reject;
this.close();
}
render() {
return <Modal visible={this.state.visible} onCancel={this.close} onOk={this.handleOk} > <div> hello </div> <div> you can check result in devtool </div> <Input onChange={e => { const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} ></Input> </Modal>
}
}
复制代码
import React from 'react';
import './App.css';
import { Button } from 'antd';
import AsyncModal from './components/async_modal';
class App extends React.Component {
handleOpenModal = async () => {
if (this.refs.asyncModal) {
const result = await this.refs.asyncModal.open();
console.log(result)
}
}
render() {
return (
<div className="App"> <Button onClick={this.handleOpenModal} > Open Modal </Button> <AsyncModal ref="asyncModal"></AsyncModal> </div>
);
}
}
export default App;
复制代码
这样,咱们就可使用await 获取到Modal内到交互结果了,而且作到了较好的解耦。
import React from 'react';
import { Modal, Input } from 'antd';
class AsyncModalBase extends React.Component {
state = {
visible: false,
}
open = () => {
this.setState({
visible: true,
});
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
close = () => {
this.setState({
visible: false,
});
if (this.reject && typeof this.reject === 'function') {
this.reject('cancel');
}
}
}
export default class AsyncModalDemo extends AsyncModalBase {
state = {
text: ''
}
handleOk = () => {
if (typeof this.resolve === 'function') {
this.resolve(this.state.text);
}
delete this.reject;
this.close();
}
render() {
return <Modal visible={this.state.visible} onCancel={this.close} onOk={this.handleOk} > <div> hello </div> <div> you can check result in devtool </div> <Input onChange={e => { const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} ></Input> </Modal>
}
}
复制代码
open 和 close method 在 AsyncModalBase内实现,在AsyncModalDemo内只须要实现handleOk就能够了。这样就复用了open和close两个method。
import React from 'react';
import { Modal, Input, Button } from 'antd';
const ModalHoc = (modalProps = {}) => DefaultComponent => class extends React.Component {
state = {
visible: false,
}
open = () => {
this.setState({
visible: true,
});
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
close = () => {
this.setState({
visible: false,
});
if (this.reject && typeof this.reject === 'function') {
this.reject('cancel');
}
}
hanldeResolve = (...params) => {
if (typeof this.resolve === 'function') {
this.resolve(...params);
}
delete this.reject;
this.close();
}
render() {
return <Modal {...modalProps} visible={this.state.visible} footer={null} // 这里作了一点改动,footer在子组件内实现 closable onCancel={this.close} > <DefaultComponent {...this.props} hanldeResolve={this.hanldeResolve} hanldeClose={this.close} ></DefaultComponent> </Modal>
}
}
class Demo extends React.Component {
state = {
text: '',
}
handleOk = () => {
this.props.hanldeResolve(this.state.text)
}
render() {
return <div> <div> hello </div> <div> you can check result in devtool </div> <Input onChange={e => { const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} ></Input> <div style={{ marginTop: 10, textAlign: 'right' }}> <Button style={{marginRight: 5}} onClick={this.props.hanldeClose}>取消</Button> <Button type="primary" onClick={this.handleOk}>肯定</Button> </div> </div>
}
}
export default ModalHoc()(Demo);
复制代码
很容易封装出了一个ModalHOC,同时作到了比较好的代码复用和解耦。这样,咱们只须要实现modal内的业务逻辑,如表单、选择器……。外层的调用方式仍是保持一致。
modal_mixin:
export default {
data() {
return {
visible: false,
}
},
watch: {
visible(val) {
if (!val) {
if (typeof this.handleClear === 'function') {
this.handleClear();
}
if (this.reject) {
this.reject('放弃操做');
}
}
}
},
methods: {
open(...params) {
this.visible = true;
if (typeof this.handleInit === 'function') {
this.handleInit(...params);
}
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
},
handleResolve(...params) {
delete this.reject;
this.visible = false;
if (this.resolve) {
this.resolve(...params);
}
},
close() {
this.visible = false;
}
}
}
复制代码
async modal:
<template>
<el-dialog :visible.sync="visible">
<div>
you can check result in devtool
</div>
<el-input v-model="text"></el-input>
<div style="text-align: right; margin-top: 15px">
<el-button size="small" @click="close">取消</el-button>
<el-button size="small" type="primary" @click="handleOk">确认</el-button>
</div>
</el-dialog>
</template>
<script>
import modal_mixin from './modal_mixin';
export default {
name: 'AayncModal',
mixins: [modal_mixin],
data() {
return {
text: ''
}
},
methods: {
handleOk() {
this.handleResolve(this.text);
}
}
}
</script>
复制代码
调用:
<template>
<div id="app">
<div>
<el-button @click="openModal">open modal</el-button>
</div>
<HelloWorld ref="asyncModal"/>
</div>
</template>
<script>
import HelloWorld from './components/AsyncModal.vue'
export default {
name: 'app',
components: {
HelloWorld
},
methods: {
async openModal() {
if (this.$refs.asyncModal) {
const result = await this.$refs.asyncModal.open();
console.log(result)
}
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
复制代码
使用mixin作代码复用。看起来彷佛比react版本更简单一些。