Browse Source

添加marquee

杨磊 7 years ago
parent
commit
d03728ca5c

+ 7 - 3
config.json

@@ -335,7 +335,6 @@
       "showDemo": true
       "showDemo": true
     },
     },
     {
     {
-      
       "name": "ShortPwd",
       "name": "ShortPwd",
       "chnName": "短密码弹层",
       "chnName": "短密码弹层",
       "desc": "6位短密码弹层",
       "desc": "6位短密码弹层",
@@ -348,8 +347,13 @@
       "desc": "公共底部菜单",
       "desc": "公共底部菜单",
       "type": "component",
       "type": "component",
       "showDemo": true
       "showDemo": true
+    },
+    {
+      "name": "Marquee",
+      "chnName": "跑马灯",
+      "desc": "文字以及内容的横向纵向轮播",
+      "type": "component",
+      "showDemo": true
     }
     }
-   
-    
   ]
   ]
 }
 }

+ 68 - 0
src/demo/marquee.vue

@@ -0,0 +1,68 @@
+<template>
+    <div>
+        <nut-demoheader
+        :name="$route.name"
+        ></nut-demoheader>
+        <h5>示例</h5>
+        <p>普通文字横向跑马灯-默认速度</p>
+        <nut-marquee class="demo1" :gap='gap'>
+            <template slot>
+                <div class="txt">我是一个轮播图1</div>
+                <div class="txt">我是一个轮播图2</div>
+                <div class="txt">我是一个轮播图2</div>
+                <div class="txt">我是一个轮播图2</div>
+                <div class="txt">我是一个轮播图2</div>
+                <div class="txt">我是一个轮播图2</div>
+                <div class="txt">我是一个轮播图2</div>
+            </template>
+        </nut-marquee>
+        <p>横向反向</p>
+        <nut-marquee class="demo1" :gap='gap' :reverse="true">
+            <template slot>
+                <div class="txt">我是一个轮播图,我有好多数字,一个屏幕看不到,只能看到一部分,轮播开始了</div>
+            </template>
+        </nut-marquee>
+        <p>纵向内容跑马灯</p>
+        <nut-marquee class="demo1" 
+            :speed='20' 
+            :height="demo3Height" 
+            :direction='v'>
+            <div class="txt1">我是一个轮播图,我有好多数字,一个屏幕看不到,只能看到一部分,轮播开始了1</div>
+            <div class="txt1">我是一个轮播图,我有好多数字,一个屏幕看不到,只能看到一部分,轮播开始了2</div>
+            <img class="img" src='//nutui.jd.com/asset/img/nutui-logo-2.png'/>
+            <div class="txt1">我是一个轮播图,我有好多数字,一个屏幕看不到,只能看到一部分,轮播开始了3</div>
+            <div class="txt1">我是一个轮播图,我有好多数字,一个屏幕看不到,只能看到一部分,轮播开始了4</div>
+        </nut-marquee>
+    </div>    
+</template>
+<script>
+export default {
+    data() {
+        return {
+            h: '1.2rem',
+            v: 'vertical',
+            demo3Height: '1.2rem',
+            gap: '.4rem'
+        }
+    }
+}
+</script>
+<style lang="scss" scoped>
+    .demo1 {
+        background: #fefad8;
+
+    }
+    .img {
+        width: 80%;
+    }
+    .txt {
+        display: inline;
+        line-height: .4rem;
+        // margin-right: .4rem;
+        white-space: nowrap;
+    }
+    .txt1 {
+        padding: .1rem;
+    }
+</style>
+

+ 7 - 0
src/package/marquee/index.js

@@ -0,0 +1,7 @@
+import Marquee from './src/marquee.vue';
+
+Marquee.install = function(Vue) {
+  Vue.component(Marquee.name, Marquee);
+};
+
+export default Marquee

+ 207 - 0
src/package/marquee/src/marquee.vue

@@ -0,0 +1,207 @@
+<template>
+    <div class="nut-marquee" :style="mainCss" ref="marquee">
+        <div class="nut-marquee-wrapper" ref='wrap'>
+            <slot></slot>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'nut-marquee',
+    props: {
+        speed: {
+            default: 10,
+            type: Number
+        },
+        height: {
+            default: 'auto',
+            type: String
+        },
+        direction: {
+            default: 'horizontal',
+            type: String,
+            validator: function (value) {
+                // 这个值必须匹配下列字符串中的一个
+                return ['horizontal', 'vertical'].indexOf(value) !== -1
+            }
+        },
+        reverse: {
+            default: false,
+            type: Boolean
+        },
+        gap: {
+            default: '0',
+            type: Number
+        }
+    },
+    data() {
+        return {
+            mainCss: {},
+            offset: {
+                x: 0,
+                y: 0
+            },
+            marquee: {
+                height:0,
+                width: 0
+            },
+            wrap: {
+                height: 0,
+                width: 0
+            }
+
+        }
+    },
+    created() {
+        this.mainCss = {
+            height: this.height 
+        }
+    },
+
+    mounted() {
+        this.$nextTick(() => {
+            this.init()
+        })
+    },
+    methods: {
+        init() {
+            this.initPosition();
+            //尺寸不需要启动轮播滚动。
+            if(!this.needRoll()) return;
+            this.start();
+        },
+        initPosition() {
+            this.marquee = {
+                height: this.$refs.marquee.clientHeight,
+                width: this.$refs.marquee.clientWidth
+            }          
+            this.wrap = {
+                height: this.$refs.wrap.clientHeight,
+                width: this.$refs.wrap.clientWidth
+            }
+            this.offset.x = this.marquee.width;
+            this.offset.y = this.marquee.height;
+            
+        },
+        start() {
+            if(['horizontal', 'vertical'].indexOf(this.direction) == -1) console.warn('参数direction有误,执行默认配置horizontal');
+            if(this.direction === 'vertical') {
+                this.startVertical();
+            } else {
+                this.startHorizontal();
+            }            
+        },
+        //判断是否需要滚动
+        needRoll() {
+            let need = true;
+            if(this.direction === 'vertical') {
+                if(this.marquee.height > this.wrap.height) {
+                    //容器高于内容
+                    need = false;
+                }
+            }else {
+                if(this.marquee.width > this.wrap.width) {
+                    need = false;
+                }
+            }
+            return need;
+        },
+
+        ///启动水平滚动,水平滚动处理区域
+        startHorizontal() {
+            this.createShadowDom();
+            if(!this.reverse) {
+                this.normalHorizontalRoll();
+            }else {
+                this.reverseHorizontalRoll();
+            }
+        },
+        //横向普通模式运动
+        normalHorizontalRoll() {
+            let _self = this;
+            let width = this.wrap.width;
+            setInterval(function() {
+                _self.setTransform(_self.$refs.wrap, `translate3d(${_self.offset.x}px, 0, 0)`);
+                _self.offset.x = _self.offset.x - 1 ;
+                if(-(_self.offset.x) > width) {
+                    _self.offset.x = 0;
+                }
+            }, this.speed)
+        },
+        //横向反向模式运动
+        reverseHorizontalRoll() {
+
+        },
+        //启动垂直滚动
+        startVertical() {
+            this.createShadowDom();
+            if(!this.reverse) {
+                this.normalVerticalRoll();
+            }else {
+                this.reverseVerticalRoll();
+            }
+        },
+        //垂直普通模式运动
+        normalVerticalRoll() {
+            let _self = this;
+            let height = this.wrap.height;
+            setInterval(function() {
+                _self.setTransform(_self.$refs.wrap, `translate3d(0, ${_self.offset.y}px, 0)`);
+                _self.offset.y = _self.offset.y - 1 ;
+                if(-(_self.offset.y) > height) {
+                    _self.offset.y = _self.marquee.height;
+                }
+            }, this.speed)
+        },
+        //垂直反向模式运动
+        reverseVerticalRoll() {
+
+        },
+        /*
+         * 功能操作区
+         */
+        //设置transform
+        setTransform (ele, val){
+            ele.style.transform = val;
+            ele.style.WebkitTransform = val;
+            ele.style.MozTransform = val;
+            ele.style.OTransform = val;
+        },
+        //无限模式中,创建dom来保证2次之间的衔接
+        createShadowDom(el) {
+            let con = this.$refs.wrap;
+            let childNodes = this.$refs.wrap.children;
+                console.log(this.$refs.wrap.children);
+                for(let i =0; i < childNodes.length; i++) {
+                    let node = childNodes[i];
+                    con.appendChild(node.cloneNode(true));
+                }
+                return;
+            if(!this.reverse == 'horizontal') {
+                let firstItem = this.$refs.wrap.firstElementChild;
+                console.log(this.$refs.wrap);
+                let cloneNode = firstItem.cloneNode(true);
+                cloneNode.style.setProperty('margin-left', this.gap);
+                con.appendChild(cloneNode);
+            }else {
+                let lastItem = this.$refs.wrap.lastElementChild;
+                let firstItem = this.$refs.wrap.firstElementChild;
+                let cloneNode = lastItem.cloneNode(true);
+                cloneNode.style.setProperty('margin-right', this.gap);
+                con.insertBefore(cloneNode, firstItem);
+            }
+
+        }
+
+    }
+}
+</script>
+<style lang='scss'>
+    .nut-marquee {
+        overflow: hidden;
+    }
+    .nut-marquee-wrapper {
+        white-space: nowrap;
+        transition: transform 0ms linear;
+    }
+</style>

+ 51 - 0
src/package/marquee/src/utils.js

@@ -0,0 +1,51 @@
+function insertKeyFrame (rule) {
+    if (document.styleSheets && document.styleSheets.length) {
+      try {
+        document.styleSheets[0].insertRule(rule, 0)
+      } catch (ex) {
+      }
+    } else {
+      var style = document.createElement('style')
+      style.innerHTML = rule
+      document.head.appendChild(style)
+    }
+  }
+  
+  function deleteKeyFrame (ruleName) {
+    var cssrules = (document.all) ? 'rules' : 'cssRules'
+    var i
+    if (document.styleSheets && document.styleSheets.length && document.styleSheets[0][cssrules]) {
+      for (i = 0; i < document.styleSheets[0][cssrules].length; i += 1) {
+        var rule = document.styleSheets[0][cssrules][i]
+        if (rule.name === ruleName || rule.selectorText === '.' + ruleName) {
+          document.styleSheets[0].deleteRule(i)
+          break
+        }
+      }
+    }
+  }
+  
+  function getWidthHeight () {
+    var w = window
+    var d = document
+    var e = d.documentElement
+    var g = d.getElementsByTagName('body')[0]
+    return {
+      width: w.innerWidth || e.clientWidth || g.clientWidth, height: w.innerHeight || e.clientHeight || g.clientHeight
+    }
+  }
+  
+  function getTextWidth (text, font) {
+    var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement('canvas'))
+    var context = canvas.getContext('2d')
+    context.font = font
+    var metrics = context.measureText(text)
+    return metrics.width
+  }
+  
+  export {
+    insertKeyFrame,
+    deleteKeyFrame,
+    getWidthHeight,
+    getTextWidth
+  }

+ 0 - 0
src/view/marquee.vue