vue項目乾貨,繼續完善

總有一個功能,你會用的到!
接上篇文章:vue項目乾貨
源碼地址css

15.關於echarts圖表及隨區域大小變化resize

建立lineChart組件,折線圖表
image.png
代碼以下:vue

<template>
    <div :id="srcData.id" class="warnCount"></div>
</template>
<script>
    import echarts from 'echarts';
    import resize from '../resize' //用於可視區域改變時resize
    export default {
        name: "chart",
        mixins: [resize],
        data() {
            return {
                chartColumn: null,
                scale: 1,
            }
        },
        props: {
            srcData: Object, //數據
            isGetData: Boolean  //獲取好數據 能夠開始繪製標記
        },
        watch: {
            isGetData(val) {
                this.drawChart();
            }
        },
        methods: {
            drawChart() {
                let me=this;
                setTimeout(() => {
                    let me = this;
                    this.chartColumn.clear();
                    this.chartColumn.setOption({
                        tooltip: {
                            trigger: 'axis',
                            confine: true
                        },
                        yAxis: {
                            name: '得分',
                            type: 'value',
                            axisLine: {
                                lineStyle: {
                                    color: '#72aafa'
                                },
                            },
                            splitLine: {
                                show:false,
                                lineStyle: {
                                    color: '#154d5a',
                                    width: 0.5
                                }
                            },
                        },
                        xAxis :{
                            type: 'time',
                            splitLine: {
                                show: false,
                                lineStyle: {
                                    color: '#72aafa',
                                    
                                }
                            },
                            axisLine: {
                                lineStyle: {
                                    color: '#72aafa'
                                }
                            },
                            
                        },
                        grid:{
                            top:'15%',
                            right:'10%',
                            left:'10%',
                            bottom:'15%'
                        },
                        series:this.srcData.sData
                    })
                }, 0);
            }
        },
        created() {
            var me = this;
        },
        updated() {
        },
        mounted() {
            let charDom = document.getElementById(this.srcData.id), me = this;
            charDom.style.height = this.srcData.height + "px";
            this.scale = window.innerWidth / 1920;
            this.chartColumn = echarts.init(charDom);
            this.chartColumn.on('click', function (params) {
                me.$emit('click', params);
            })
        },
        beforeDestroy() {
            if (this.chartColumn) {
                this.chartColumn.clear()
            }
        },
        destroy() {
            if (this.chartColumn) {
                this.chartColumn.dispose()
                this.chartColumn = null;
            }
        },
        components: {}
    }
</script>
<style scoped lang="scss">
    .warnCount {
        width: 100%;
        height: 350px;
    }
</style>

接下來開始使用該組件:
image.png
傳值:git

warnCountTrendData: {
    id: 'warnCountTrend',
    height: 350,
    sData:[
        {
            name:'競逐對',
            symbol:'circle',
            symbolSize:6,
            type:'line',
            lineStyle:{
                width:1
            },
            data:[
                {value:["2020-01-01 00:00:00",0]},
                {value:["2020-01-02 00:00:00",0]},
                {value:["2020-01-04 01:01:01",200]},
                {value:["2020-01-07 01:01:01",200]}

            ]
        },
        {
            name:'競逐對1',
            symbol:'circle',
            symbolSize:6,
            type:'line',
            lineStyle:{
                width:1
            },
            data:[
                {value:["2020-01-02 00:00:00",0]},
                {value:["2020-01-06 04:01:00",100]},
                {value:["2020-01-07 01:01:01",200]}
            ]
        }
    ]
}

當窗口改變時window.onresize能夠被監聽到,但當導航欄收起時監聽不到,此項目的解決方案是安裝:element-resize-detector
resize.js文件:github

import {debounce} from '../common/util';
import elementResizeDetectorMaker from 'element-resize-detector'
export default {
    data() {
        return {
            $_sidebarElm: null
        }
    },
    mounted() {
        let me=this;
        this.__resizeHandler = debounce(() => {
            if (this.chartColumn) {
                this.chartColumn.resize()
            }
        }, 100)
        window.addEventListener('resize', this.__resizeHandler);
        const erd = elementResizeDetectorMaker()
        erd.listenTo(document.getElementsByClassName("contentBox"),(element)=>{
           me.$nextTick(()=>{
                me.resize()
            })
        })
    },
    beforeDestroy() {
        window.removeEventListener('resize', this.__resizeHandler);
    },
    methods: {
        resize() {
            this.__resizeHandler()
        }
    }
}

debounce爲函數防抖方法:web

export const debounce = (func, wait, immediate) => {
    let timeout, args, context, timestamp, result

    const later = function () {
        // 據上一次觸發時間間隔
        const last = +new Date() - timestamp

        // 上次被包裝函數被調用時間間隔 last 小於設定時間間隔 wait
        if (last < wait && last > 0) {
            timeout = setTimeout(later, wait - last)
        } else {
            timeout = null
            // 若是設定爲immediate===true,由於開始邊界已經調用過了此處無需調用
            if (!immediate) {
                result = func.apply(context, args)
                if (!timeout) context = args = null
            }
        }
    }

    return function (...args) {
        context = this
        timestamp = +new Date()
        const callNow = immediate && !timeout
        // 若是延時不存在,從新設定延時
        if (!timeout) timeout = setTimeout(later, wait)
        if (callNow) {
            result = func.apply(context, args)
            context = args = null
        }

        return result
    }
}

實現效果:
segmentfault

16.抽屜

經過drawer控制抽屜展現隱藏
image.png瀏覽器

<el-button @click="showDrawer" type="primary" class='showBtn' :style='sty'>
        <i class='iconfont iconshezhi' v-if='!drawer'></i>
        <i class='iconfont iconguanbi' v-else></i>
    </el-button>
    <el-drawer  :visible.sync="drawer" direction="rtl" style='position:absolute' @close='onClose'>
    <span class='drawTitle'>設置</span>
    <div style='margin:0 auto;width:100%;'>
        <el-form ref="form" label-width="80px">
            <el-form-item label="選擇主題">
                <el-select v-model="value" placeholder="請選擇" @change='changeColor'>
                    <el-option
                    v-for="item in options"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                    </el-option>
                </el-select>
            </el-form-item>
        </el-form>
    </div>
</el-drawer>

再來控制控制按鈕的樣式:sass

.showBtn {
    position:absolute;
    top:50%;
    transform :translateY(-50%);
    z-index:100000;
    transition: right .3s;
    padding:10px!important;
    i {
        font-size:20px;
    }
}
.drawTitle {
    position: absolute;
    top: 4%;
    left: 5%;
    font-weight: 700;
    color: #666;
    font-size: 17px;
}

方法邏輯:session

showDrawer:function(){
    let me=this;
    me.drawer = !me.drawer;
    me.value=sessionStorage.getItem('theme');
    me.sty.right=me.drawer?'30%':'0' //按鈕位置
},
onClose:function(){
    let me=this;
    me.sty.right='0'
}

實現效果:
image.pngapp

17.換膚功能

增長以下兩個文件(需安裝sass)
image.png
mixin.scss

@mixin get-theme-value($type, $value, $css-key, $css-value) {
    @each $themename , $theme in $themes {
        [data-theme = '#{$themename}'] & {
            $_type: map-get($theme, $type);
            #{$css-key}: #{$css-value} map-get($_type , $value );
        }
    }
}

@mixin get-color-value($type, $value) {
    @each $themename , $theme in $themes {
        [data-theme = '#{$themename}'] & {
            $_type: map-get($theme, $type);
            #{$type}-color: map-get($_type , $value );
        }
    }
}

@mixin background($color){
    @include get-theme-value('background', $color, 'background', '');
}
@mixin background-color($color){
    @include get-color-value('background', $color);
}

@mixin font-color($color) {
    @include get-theme-value('font', $color, 'color', '');
}

@mixin border-color($color) {
    @include get-color-value('border', $color);
}
@mixin border($color, $css-key:'border', $css-value:'1px solid') {
    @include get-theme-value('border', $color,  $css-key , $css-value)
}

@mixin box-shadow($color, $css-value) {
    @include get-theme-value('boxShadow', $color, 'box-shadow', $css-value)
}
@mixin common-link-font($size: 1.2) {
    font-size: #{$size}rem; font-weight: 600;
    &:hover,
    &.selected{
        @include font-color('color4');
    }
    @include font-color('color1');
}
@mixin common-font($size: 1.2, $font-weight: 400) {
    font-size: #{$size}rem; font-weight: $font-weight;
    @include font-color('color1');
}

@mixin flex($justify: flex-start, $align-items: center, $dir: row, $wrap: nowrap, $align-content: stretch) {
  display: flex;
  flex-flow: $dir $wrap;
  justify-content: $justify;
  align-items: $align-items;
  align-content: $align-content;
}

theme.css 定義兩套主題

@import './mixin.scss';
// default theme

$default-theme : (
  font: (
    color1: #16284c,
  ),
  border: (
    color1: #16284c,
  ),
  background: (
    color1: #16284c,
  ),
  boxShadow: (
    color1: rgba(0,0,0,.3)
  )
);

//紅色主題
$red-theme : (
  font: (
    color1: red
  ),
  border: (
    color1: red
  ),
  background: (
    color1: red
  ),
  boxShadow: (
    color1: rgba(0,0,0,.3)
  )
);

$themes: (
  default-theme: $default-theme,
  red-theme: $red-theme
);

App.vue

<template>
    <div id="app">
        <transition name="fade" mode="out-in">
            <router-view></router-view>
        </transition>
    </div>
</template>
<script>
    export default {
        name: 'app',
        data(){
          return {
              getNowThemeInfo:'' //初始主題
          }
        },
        mounted() {
          let me=this;  
          me.getNowThemeInfo=sessionStorage.getItem('theme');
          me.setBodyTheme();
          
        },
        methods: {
            setBodyTheme() {
                document.body.dataset.theme = this.getNowThemeInfo;
            }
        },
        components: {}
    }

</script>

<style lang="scss">
    body {
        margin: 0px;
        padding: 0px;
        /*background: url(assets/bg1.jpg) center !important;
            background-size: cover;*/
        // background: #1F2D3D;
        font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
        font-size: 14px;
        -webkit-font-smoothing: antialiased;
    }

    #app {
        position: absolute;
        top: 0px;
        bottom: 0px;
        width: 100%;
    }

    .el-submenu [class^=fa] {
        vertical-align: baseline;
        margin-right: 10px;
    }

    .el-menu-item [class^=fa] {
        vertical-align: baseline;
        margin-right: 10px;
    }

    .toolbar {
        background: #f2f2f2;
        padding: 10px;
        //border:1px solid #dfe6ec;
        margin: 10px 0px;
        .el-form-item {
            margin-bottom: 10px;
        }
    }

    .fade-enter-active,
    .fade-leave-active {
        transition: all .2s ease;
    }

    .fade-enter,
    .fade-leave-active {
        opacity: 0;
    }
</style>

當某個元素的顏色信息須要隨主題改變時,須要這樣定義顏色信息
image.png
你會發現瀏覽器中樣式使這樣寫的
image.png
基本換膚功能就實現了,下面介紹下如何切換(此項目將主題信息存儲在session中)
main.js中增長以下方法,監聽session

Vue.prototype.resetSetItem = function (key, newVal) {
  if (key =='theme') {
      // 建立一個StorageEvent事件
      var newStorageEvent = document.createEvent('StorageEvent');
      const storage = {
          setItem: function (k, val) {
              sessionStorage.setItem(k, val);
              // 初始化建立的事件
              newStorageEvent.initStorageEvent('setItem', false, false, k, null, val, null, null);
              // 派發對象
              window.dispatchEvent(newStorageEvent)
          }
      }
      return storage.setItem(key, newVal);
  }
}

在app.vue中監聽變化

window.addEventListener('setItem', ()=> {
    var val = sessionStorage.getItem('theme');
    console.log(val);
    this.getNowThemeInfo=sessionStorage.getItem('theme');
    this.setBodyTheme();
})

在改變主題信息時記得存session裏theme
錄屏工具打不開了...效果先看項目吧

將不斷更新完善,期待您的批評指正!

相關文章
相關標籤/搜索