vue插件開發練習--實用彈窗

1.前言

上回說了組件(vue組件開發練習--焦點圖切換)的一個練習項目,此次換下口味,說下vue的插件練手的項目。相對於如今以前的焦點圖切換的組件,這個可能就更簡單了,基本就是熟悉下插件開發的步驟就能夠了!這個項目,我更建議你們動手練習了,這個彈窗比以前的焦點圖更加的實用性,也更經常使用。同時也能讓你們熟悉下vue的插件開發的流程。代碼一樣,我會上傳到github(ec-dialog),須要的能夠直接去看代碼!css

建議
1.下面的步驟,最好在本身本地上跑起來,根據文章的步驟,逐步完成,若是隻看代碼,很容易懵逼的。
2.若是不清楚哪一個代碼有什麼做用,可能本身調試下,把代碼去掉後,看下有什麼影響,就很容易想出代碼有什麼做用了!

2.項目目錄

clipboard.png

仍是一個很簡單的目錄,各個目錄不知道有什麼用的,能夠移步去看我上一篇文章。和組件開發的目錄相比,區別就在於src/js/components這個文件夾上。html

3.開發過程

3-1.把項目跑起來

首先,先弄src/js/components/alert這個組件。仍是同樣,,先在src/js/components/alert/src/main.vue。輸出‘守候’。代碼以下vue

<template>
    <transition name="ec">
        <div class="ec">
            守候
        </div>
    </transition>
</template>
<script>
    export default {
        data () {
            return {
                name: 'ec-alert',
            }
        },
        computed: {},
        mounted () {
        },
        methods: {
        }
    }
</script>

而後來到'alert/index.js'。這個術語叫什麼什麼文件,我不太清楚,暫時就叫,插件配置文件吧!代碼以下(注意看註釋)git

import Vue from 'vue'
import AlertComponent from './src/main.vue'
//合併對象函數,這個方法是會改變,第一個參數的值的
function merge(target) {
    for (let i = 1, j = arguments.length; i < j; i++) {
        let source = arguments[i] || {};
        for (let prop in source) {
            if (source.hasOwnProperty(prop)) {
                let value = source[prop];
                if (value !== undefined) {
                    target[prop] = value;
                }
            }
        }
    }
    return target;
};
let instance;
//extend 是構造一個組件的語法器.傳入參數,返回一個組件
let AlertConstructor = Vue.extend(AlertComponent);

let initInstance = ()=>{
    //實例化ConfirmConstructor組件
    instance = new AlertConstructor({
        el: document.createElement('div')
    });
    //添加到boby
    document.body.appendChild(instance.$el);
}

let Alert = (options={}) => {
    //初始化
    initInstance();
    // 將單個 confirm instance 的配置合併到默認值(instance.$data,就是main.vue裏面的data)中
    merge(instance.$data, options);
    //返回Promise
    return new Promise((resolve, reject)=>{
        instance.show = true;
        let success = instance.success;
        let cancel = instance.cancel;
        instance.success = () => {
            //先執行instance.success(main.vue裏面的success函數)
            success();
            //再執行自定義函數
            resolve('ok');
        }
    });

}
export default Alert;

而後來到components/js/index.js這個文件,配置組件和API,代碼以下程序員

import alert from './alert/index.js'

const install = function(Vue) {
    //註冊全局組件
    Vue.component(alert.name, alert)
    //添加全局API
    Vue.prototype.$alert = alert
}
export default install

而後在模板文件,index.html裏面設置一個div,方便掛載測試github

<!DOCTYPE html>
<html lang="en">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
</div>
</body>
</html>

而後在入口文件index.js裏面,使用插件npm

require("./index.html");
//引入sass
require("./src/sass/com.scss");
import Vue from 'vue'
import dialog from './src/js/components/index';
Vue.use(dialog)
let App = new Vue({
    el: '#app',
    data(){
        return {
            'name': 'index'
        }
    },
    mounted(){
        this.$alert();
    }
});

而後,命令行 $ npm run dev,結果完美segmentfault

clipboard.png

3-2.樣式修改

完成了上一步,這個插件的一大半就算完成了!剩下的工做主要開發的就是在components/../main.vue這文件開發。
首先,先別急寫代碼,想一下,一個彈窗大概須要什麼字段。sass

clipboard.png

參考上面,發現有一個標題,一個內容,一個按鈕文字。最後還須要一個變量,控制彈窗是否顯示。而後一個點擊按鈕的操做函數。而後還有樣式,大概以下微信

clipboard.png

樣式這個很少說,其餘的字段,一個蘿蔔一個坑的填進去就好,代碼以下

<template>
    <transition name="ec">
        <div v-if="show" class="ec">
            <div class="ec-box">
                <div class="ec-box-inner">
                    <div class="ec-title" v-if="title">{{title}}</div>
                    <div class="ec-content">{{content}}</div>
                </div>
                <div class="ec-box-buttons">
                    <span class="ec-btn-success" @click="success">{{submitText}}</span>
                </div>
            </div>
        </div>
    </transition>
</template>
<script>
    export default {
        data () {
            return {
                name:'ec-alert',
                show: false,
                title: '提示',
                content: '',
                submitText: '肯定',
                cancelText: '取消'
            }
        },
        computed: {},
        mounted () {
        },
        methods: {
            success () {
                this.show = false;
            }
        }
    }
</script>
<style lang="scss" scoped>

    .ec {
        background: rgba(00, 00, 00, .5);
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        .ec-box {
            width: 80%;
            max-width: 400px;
            top: 200px;
            position: absolute;
            left: 0;
            right: 0;
            margin: auto;
            background: #fff;
            box-sizing: border-box;
            padding: 20px;
            border-radius: 6px;

        }
        .ec-title {
            padding-left: 0;
            margin-bottom: 0;
            font-size: 16px;
            font-weight: 700;
            height: 18px;
            color: #333;
        }
        .ec-content {
            padding: 14px 0;
            line-height: 24px;
            color: #48576a;
            font-size: 14px;
        }
        .ec-box-buttons {
            text-align: right;
        }
        .ec-btn-success {
            background: #20a0ff;
            border-color: #20a0ff;
            display: inline-block;
            line-height: 1;
            white-space: nowrap;
            cursor: pointer;
            color: #fff;
            margin: 0;
            padding: 10px 15px;
            border-radius: 4px;
        }
        .ec-btn-cancel {
            display: inline-block;
            line-height: 1;
            white-space: nowrap;
            cursor: pointer;
            background: #fff;
            border: 1px solid #c4c4c4;
            color: #1f2d3d;
            margin: 0;
            padding: 10px 15px;
            border-radius: 4px;
        }
    }
    .ec-enter {
        opacity: 0;
        .ec-box {
            transform:scale(0);
        }
    }

    .ec-enter-active {
        transition: opacity .4s;
        .ec-box {
            transition: transform .4s;
        }
    }
    .ec-leave-active{
        transition: opacity .2s;
        .ec-box {
            transition: transform .2s;
        }
    }
    .ec-leave-active {
        opacity: 0;
    }
</style>

運行效果

clipboard.png

3-3.使用插件

你們知道,在前面步驟,'alert/index.js'這裏就已經返回的一個Promise。因此,用法就是像Promise那樣使用!

clipboard.png

因此在入口文件,index.js裏面直接寫

mounted(){
    this.$alert({
        title:'提示2',
        content:'這裏是提示內容2'
    }).then(()=>{
        this.name='守候'
        alert(this.name)
    })
}

運行效果

clipboard.png

4.其它彈窗

仍是那句話,程序員不會知足於現狀,只有一種彈窗,怎麼夠,下面我再增長一種,和上面那個基本同樣,就是多了一個取消按鈕而已。
這裏我就再講一個簡單的栗子,至於彈窗的樣式,太多了,我在這裏就不展開說了,你們須要的可進行拓展。

首先,建立這個目錄(能夠直接把alert那個目錄拷貝過來,而後再修改幾下就完事了)

clipboard.png

而後,針對comfirm/src/main.vue文件,添加下面的代碼(下面的代碼基本就是從alert/src/main.vue拷貝過來的,就是增長一個取消按鈕的對應一個字段和操做函數)

<template>
    <transition name="ec">
        <div v-if="show" class="ec">
            <div class="ec-box">
                <div class="ec-box-inner">
                    <div class="ec-title" v-if="title">{{title}}</div>
                    <div class="ec-content">{{content}}</div>
                </div>
                <div class="ec-box-buttons">
                    <span class="ec-btn-success" @click="success">{{submitText}}</span>
                    <span class="ec-btn-cancel" @click="cancel">{{cancelText}}</span>
                </div>
            </div>
        </div>
    </transition>
</template>
<script>
    export default {
        data () {
            return {
                name:'ec-comfirm',
                show: false,
                title: '提示',
                content: '',
                submitText: '肯定',
                cancelText: '取消'
            }
        },
        computed: {},
        mounted () {
        },
        methods: {
            success () {
                this.show = false;
            },
            cancel () {
                this.show = false;
            }
        }
    }
</script>
<style lang="scss" scoped>
    .ec {
        background: rgba(00, 00, 00, .5);
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: 9999;
        .ec-box {
            width: 80%;
            max-width: 400px;
            top: 200px;
            position: absolute;
            left: 0;
            right: 0;
            margin: auto;
            background: #fff;
            box-sizing: border-box;
            padding: 20px;
            border-radius: 6px;

        }
        .ec-title {
            padding-left: 0;
            margin-bottom: 0;
            font-size: 16px;
            font-weight: 700;
            height: 18px;
            color: #333;
        }
        .ec-content {
            padding: 14px 0;
            line-height: 24px;
            color: #48576a;
            font-size: 14px;
        }
        .ec-box-buttons {
            text-align: right;
        }
        .ec-btn-success {
            background: #20a0ff;
            border-color: #20a0ff;
            display: inline-block;
            line-height: 1;
            white-space: nowrap;
            cursor: pointer;
            color: #fff;
            margin: 0;
            padding: 10px 15px;
            border-radius: 4px;
        }
        .ec-btn-cancel {
            display: inline-block;
            line-height: 1;
            white-space: nowrap;
            cursor: pointer;
            background: #fff;
            border: 1px solid #c4c4c4;
            color: #1f2d3d;
            margin: 0;
            padding: 10px 15px;
            border-radius: 4px;
        }
    }
    .ec-enter {
        opacity: 0;
        .ec-box {
            transform:scale(0);
        }
    }

    .ec-enter-active {
        transition: opacity .4s;
        .ec-box {
            transition: transform .4s;
        }
    }
    .ec-leave-active{
        transition: opacity .2s;
        .ec-box {
            transition: transform .2s;
        }
    }
    .ec-leave-active {
        opacity: 0;
    }
</style>

而後就是comfirm/index.js(也是基本拷貝的,我就截圖,告訴你們改哪裏吧,這個得稍微細看才知道改哪裏)

clipboard.png

clipboard.png

而後components/index.js

import comfirm from './comfirm/index.js'
import alert from './alert/index.js'

const install = function(Vue) {
    //註冊全局組件
    Vue.component(comfirm.name, comfirm)
    Vue.component(alert.name, alert)
    //添加全局API
    Vue.prototype.$confirm = comfirm
    Vue.prototype.$alert = alert
}
export default install

最後在入口文件,index.js使用

require("./index.html");
//引入sass
require("./src/sass/com.scss");
import Vue from 'vue'
import dialog from './src/js/components/index';
Vue.use(dialog)
let App = new Vue({
    el: '#app',
    data(){
        return {
            'name': 'index'
        }
    },
    mounted(){
        this.$confirm({
            title:'提示',
            content:'這裏是提示內容',
            submitText:'提交',
            cancelText:'返回'
        }).then(()=>{
            this.$alert({
                title:'提示2',
                content:'這裏是提示內容2'
            }).then(()=>{
                this.name='守候'
                alert(this.name)
            })
        }).catch((err)=>{
            alert(err)
        })
    }
});

運行結果,就是這樣

clipboard.png

5.小結

一個簡單的彈窗就到這裏了,很簡單,可是在我開發那裏仍是能用,能暫時知足。可是這個確定是須要維護的,畢竟不少的項目都須要彈窗。你們也根據本身的須要進行拓展!以上的案例也很簡單,容易懂。基本都是記流程。可是這個我很建議你們邊動手,邊看文章。這個可讓本身練習下基於vue開發插件,是一個不錯的練習,但願能幫到你們學習到新的知識!最後,若是以爲文章那裏寫的很差或者寫錯了,歡迎指出!

-------------------------華麗的分割線--------------------
想了解更多,關注關注個人微信公衆號:守候書閣

clipboard.png

相關文章
相關標籤/搜索