React造轮子-自定义组件开发toast, confirm

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

一、toast组件开发

1.1先写UI

import React, {Component} from 'react'
import './style.css'

class Swiper extends Component {
    render() {
        console.log(this.props.swiperList[0].src.default )
        return (
            <div className={'my-swiper'}>
                {
                    this.props.swiperList && this.props.swiperList.length > 0 && this.props.swiperList.map( (v,i) => (
                        <div className={'my-swiper-item'} key={i}>
                            <a href={v.url} target={'_blank'} rel='noreferrer noopener'>
                                <img src={v.src.default}  alt={""} />
                            </a>
                        </div>
                    ))
                }
            </div>
        )
    }
}

export default Swiper

复制代码
.my-toast {
    position: fixed;
    width: auto;
    height: auto;
    padding: 10px;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
    background-color: rgba(0,0,0,0.8);
    z-index: 100;
    color: #ffffff;
    border-radius: 4px;
}

复制代码

效果

image.png

1.2 在具体业务中使用

如下图校验用户名密码弹框

image.png

通过封装toast组件实现自定义文案, 定时隐藏, 隐藏回调函数

image.png

app.js
import React from 'react'
import './assets/css/app.css'
import  Toast from  './component/toast'

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {
            username: '',
            password: ''
        };
    }

    // 登录方法
    confirmLogin() {
        console.log(this.state.username,'用户名')
        console.log(this.state.password,'密码')
        if(this.state.username.match(/^\s*$/)) {
          return  Toast({
                text: '请输入用户名',
                duration: 500,
                callback: () => {
                    console.log('用户名弹框关闭...')
                }
            })``
        }
        if(this.state.password.match(/^\s*$/)) {
          return  Toast({
                text: '请输入密码',
                duration: 500,
                callback: () => {
                  console.log('密码弹框关闭...')
                }
            })
        }
    }

    // 渲染dom
    render() {
        return (
            <div className="App">
                <input value={this.state.username} onChange={e => {this.setState( {username: e.target.value})}} />
                <br/>
                <input type={'password'} value={this.state.password} onChange={e => {this.setState( {password: e.target.value})}} />
                <br/>
                <button onClick={this.confirmLogin.bind(this)}>登录</button>
            </div>
        )
    }
}

export default App;

复制代码
index.js
import React from 'react'
import ReactDom from 'react-dom'
import Toast from "./toast";

export default function (opts) {
    console.log(opts)
    let duringTime = opts.duration || 1500
    let div = document.createElement('div')
    document.body.appendChild(div)
    // 将Toast和div挂载到render上
    let toastInit = ReactDom.render(<Toast/>,div)
    toastInit.setOpts(opts)
    // 自动隐藏toast
    setTimeout(()=> {
        document.body.removeChild(div)
        // 关闭弹框回调
        if(opts.callback && typeof opts.callback === 'function') {
            opts.callback()
        }
    },duringTime)
}

复制代码
toast.js
import React from 'react'
import './style.css'

export default class Toast extends React.Component {
    constructor() {
        super();
        this.state = {
            text: ''
        }
    }

    setOpts(opts) {
        this.setState({text: opts.text})
    }

    render() {
        return (
            <div className={'my-toast'}>
                {this.state.text}
            </div>
        )
    }
}



复制代码

效果

image.png

加上淡入淡出效果

定义动画

.my-toast {
    position: fixed;
    width: auto;
    height: auto;
    padding: 10px;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
    background-color: rgba(0,0,0,0.8);
    z-index: 100;
    color: #ffffff;
    border-radius: 4px;
    animation: showToast 0.3s forwards;
}

@keyframes showToast {
    0%{opacity: 0}
    100%{opacity: 1}
}
@keyframes hideToast {
    0%{opacity: 1}
    100%{opacity: 0}
    \
}

复制代码

淡出

 // 自动隐藏toast
    setTimeout(()=> {
        div.querySelector('.my-toast').style.animation = 'hideToast 0.3s forwards'
        // 300ms以后执行隐藏动画效果
        setTimeout(()=>{
            document.body.removeChild(div)
            // 关闭弹框回调
            if(opts.callback && typeof opts.callback === 'function') {
                opts.callback()
            }
        },300)
    },duringTime)
复制代码

效果

image.png

二、comfirm组件开发

2.1 老规矩先撸UI

import React from 'react'
import './style.css'

export default class Confirm extends React.Component {
    constructor() {
        super();
        this.state = {

        }
    }

    render() {
        return (
            <div className={'my-confirm'}>
                <div className={'message'}>
                    <div className={'title'}>确认要删除吗?</div>
                    <div className={'btn-group'}>
                        <div className={'btn'}>取消</div>
                        <div className={'btn'}>确定</div
                    </div>
                </div>
            </div>
        )
    }
}

复制代码
.my-confirm {
    position: fixed;
    font-size: 16px;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 100;
    background-color: rgba(0,0,0,0.8);
}
.message {
    position: absolute;
    width: 300px;
    height: 150px;
    border-radius: 4px;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    z-index: 1;
    background-color: #fff;
}
.title {
    margin-top: 40px;
    text-align: center;
}
.btn-group {
    margin-top: 40px;
    display: flex;
    align-items: center;
}
.btn {
    flex: 1;
    text-align: center;
    cursor: pointer;
}

复制代码

效果

image.png

举个例子, 删除数据前提示

2021-06-02-14-48-00.gif

完整代码
import React from 'react'
import './assets/css/app.css'
import  Toast from  './component/toast'
import Confirm from './component/comfirm'

class App extends React.Component {
    // 构造器
    constructor() {
        super();
        this.state = {
            username: '',
            password: '',
            userList: [
                {
                    username: '张三',
                }, {
                    username: '李四',
                }, {
                    username: '王五',
                },
            ]
        };
    }

    // 登录方法
    confirmLogin() {
        console.log(this.state.username,'用户名')
        console.log(this.state.password,'密码')
        if(this.state.username.match(/^\s*$/)) {
            return  Toast({
                text: '请输入用户名',
                duration: 500,
                callback: () => {
                    console.log('用户名弹框关闭...')
                }
            })
        }
        if(this.state.password.match(/^\s*$/)) {
            return  Toast({
                text: '请输入密码',
                duration: 1000,
                callback: () => {
                    console.log('密码弹框关闭...')
                }
            })
        }
    }

    // 删除方法
    del(index) {
        Confirm(
            '确认要删除吗?',
            [
                    {
                        text: '取消',
                        onPress: () => {
                            console.log('取消')
                        }
                    },{
                        text: '确定',
                        onPress: () => {
                            let userList = this.state.userList
                            console.log(`删除了${ userList[index].username}`)
                            userList.splice(index,1)
                            this.setState({userList})
                            console.log('确定')
                        }
                    }
                ]
            )
    }

    // 渲染dom
    render() {
        return (
            <div className="App">
                <input value={this.state.username} onChange={e => {this.setState( {username: e.target.value})}} />
                <br/>
                <input type={'password'} value={this.state.password} onChange={e => {this.setState( {password: e.target.value})}} />
                <br/>
                <button onClick={this.confirmLogin.bind(this)}>登录</button>
                <ul>
                    {
                        this.state.userList.length > 0 && this.state.userList.map((item,index) => {
                            return (
                                <li key={index}>{item.username}<button onClick={this.del.bind(this,index)}>删除</button>
                                </li>
                            )
                        })
                    }
                </ul>
            </div>
        )
    }
}

export default App;

复制代码
import React from 'react'
import ReactDom from 'react-dom'
import Confirm from "./confirm";

export default function (title ='', btnList =[]) {
    let div = document.createElement('div')
    document.body.appendChild(div)
    let initDom = ReactDom.render(<Confirm/> , div)
    initDom.setData(title,btnList,div)
}

复制代码
import React from 'react'
import './style.css'

export default class Confirm extends React.Component {
    constructor() {
        super();
        this.state = {
            title: '',
            btnList: []
        }
        this.div = null
    }

    // 设置数据
    setData(title,btnList,div) {
        this.div = div
        this.setState({title,btnList})
    }

    // 确认弹框点击事件
    handleBtnClick(index) {
        console.log(index)
        // 关闭确认弹
        document.body.removeChild(this.div)
        let cb = this.state.btnList[index].onPress
        if(cb && typeof cb === 'function' && index === 1) {
            cb()
        }
    }

    render() {
        return (
            <div className={'my-confirm'}>
                <div className={'message'}>
                    <div className={'title'}>{this.state.title}</div>
                    <div className={'btn-group'}>
                        {
                            this.state.btnList.length > 0 && this.state.btnList.map((item,index) => {
                                return (
                                    <div className={'btn'} key={index} onClick={this.handleBtnClick.bind(this,index)}>{item.text}</div>
                                )
                            })
                        }
                    </div>
                </div>
            </div>
        )
    }
}

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享