浏览代码

feat: barrage 增加slot模式,demo及文档完善 (#1699)

Ymm 3 年之前
父节点
当前提交
5c4e7722a8

+ 14 - 3
src/packages/__VUE/barrage/demo.vue

@@ -4,6 +4,15 @@
     <nut-cell>
       <nut-barrage ref="danmu" :danmu="list"></nut-barrage>
     </nut-cell>
+    <h2>{{ translate('slotTitle') }}</h2>
+    <nut-cell>
+      <nut-barrage ref="danmu">
+        <span>aaa</span>
+        <span>bbb</span>
+        <span>ccc</span>
+        <span>ddd</span>
+      </nut-barrage>
+    </nut-cell>
     <div class="test">
       <button @click="addDanmu" class="add nut-button--primary">{{ translate('btn1') }}</button>
     </div>
@@ -11,7 +20,7 @@
 </template>
 
 <script lang="ts">
-import { onMounted, ref } from 'vue';
+import { ref } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { createDemo, translate } = createComponent('barrage');
 import { useTranslate } from '@/sites/assets/util/useTranslate';
@@ -19,10 +28,12 @@ const initTranslate = () =>
   useTranslate({
     'zh-CN': {
       basic: '基本用法',
+      slotTitle: 'slot 用法',
       btn1: '随机添加'
     },
     'en-US': {
       basic: 'Basic Usage',
+      slotTitle: 'slot usage',
       btn1: 'Random addition'
     }
   });
@@ -30,8 +41,8 @@ export default createDemo({
   props: {},
   setup() {
     initTranslate();
-    const inputVal = ref<any>('');
-    const danmu = ref<any>(null);
+    const inputVal = ref('');
+    const danmu = ref();
     let list = ref(['画美不看', '不明觉厉', '喜大普奔', '男默女泪', '累觉不爱', '爷青结']);
     function addDanmu() {
       let n = Math.random();

+ 17 - 0
src/packages/__VUE/barrage/doc.en-US.md

@@ -57,6 +57,23 @@ export default {
 
 :::
 
+### slot usage
+
+:::demo
+
+```html
+<template>
+  <nut-barrage>
+    <span>aaa</span>
+    <span>bbb</span>
+    <span>ccc</span>
+    <span>ddd</span>
+  </nut-barrage>
+</template>
+```
+
+:::
+
 
 ## API
 

+ 17 - 0
src/packages/__VUE/barrage/doc.md

@@ -57,6 +57,23 @@ export default {
 
 :::
 
+### slot 用法
+
+:::demo
+
+```html
+<template>
+  <nut-barrage>
+    <span>aaa</span>
+    <span>bbb</span>
+    <span>ccc</span>
+    <span>ddd</span>
+  </nut-barrage>
+</template>
+```
+
+:::
+
 
 ## API
 

+ 27 - 18
src/packages/__VUE/barrage/index.scss

@@ -1,3 +1,11 @@
+.slotContainer {
+  > * {
+    opacity: 0;
+  }
+  > .dmitem {
+    opacity: 1;
+  }
+}
 .nut-barrage {
   position: absolute;
   left: 0;
@@ -27,24 +35,6 @@
       animation-play-state: running;
     }
   }
-  @keyframes moving {
-    from {
-      transform: translateX(100%);
-    }
-    to {
-      transform: translateX(-250%);
-      // transform: translateX(-180%);
-      // transform: translateX(var(--move-distance));
-    }
-  }
-  @-webkit-keyframes moving {
-    from {
-      -webkit-transform: translateX(100%);
-    }
-    to {
-      transform: translateX(-250%);
-    }
-  }
 }
 .nut-theme-dark {
   .nut-barrage {
@@ -53,3 +43,22 @@
     }
   }
 }
+
+// @keyframes moving {
+//   from {
+//     transform: translateX(100%);
+//   }
+//   to {
+//     transform: translateX(-150%);
+//     // transform: translateX(-180%);
+//     // transform: translateX(var(--move-distance));
+//   }
+// }
+// @-webkit-keyframes moving {
+//   from {
+//     -webkit-transform: translateX(100%);
+//   }
+//   to {
+//     transform: translateX(-150%);
+//   }
+// }

+ 82 - 38
src/packages/__VUE/barrage/index.taro.vue

@@ -1,6 +1,17 @@
 <template>
   <view class="dmBody" :class="classes">
-    <view class="dmContainer" id="dmContainer">
+    <div ref="dmContainer" class="dmContainer slotContainer" v-if="$slots.default">
+      <slot></slot>
+      <view
+        v-for="(item, index) of danmuListSlots"
+        :key="'danmu' + index"
+        :class="['dmitem', 'dmitem' + danmuList.length + index, 'move']"
+        :style="styleList[index]"
+      >
+        {{ item.length > 8 ? item.substr(0, 8) + '...' : item }}
+      </view>
+    </div>
+    <view class="dmContainer" id="dmContainer" v-else>
       <view
         v-for="(item, index) of danmuList"
         :key="'danmu' + index"
@@ -13,18 +24,7 @@
   </view>
 </template>
 <script lang="ts">
-import {
-  computed,
-  onMounted,
-  ref,
-  reactive,
-  toRefs,
-  watch,
-  nextTick,
-  onUnmounted,
-  onDeactivated,
-  getCurrentInstance
-} from 'vue';
+import { computed, onMounted, ref, reactive, watch, onUnmounted, onDeactivated, useSlots } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import Taro from '@tarojs/taro';
 const { componentName, create } = createComponent('barrage');
@@ -41,7 +41,7 @@ export default create({
     },
     speeds: {
       type: Number,
-      default: 2000
+      default: 800
     },
     rows: {
       type: Number,
@@ -58,9 +58,12 @@ export default create({
   },
   emits: ['click'],
 
-  setup(props, { emit }) {
+  setup(props, { slots }) {
+    const slotDefault = !!useSlots().default;
+
     const timeId = ref(new Date().getTime());
-    const danmuList = ref<any[]>(props.danmu);
+    const danmuList = ref<any>(props.danmu);
+    const danmuListSlots = ref<any>([]);
     const rows = ref<number>(props.rows);
     const top = ref<number>(props.top);
     const speeds = props.speeds;
@@ -74,7 +77,12 @@ export default create({
     });
 
     onMounted(() => {
-      runStep();
+      if (slotDefault) {
+        danmuList.value = slots?.default?.();
+        runStep();
+      } else {
+        runStep();
+      }
     });
 
     onUnmounted(() => {
@@ -87,7 +95,7 @@ export default create({
 
     watch(
       () => props.danmu,
-      (newValue, oldVlaue) => {
+      (newValue) => {
         danmuList.value = [...newValue];
       }
     );
@@ -96,8 +104,7 @@ export default create({
       danmuList.value = [...danmuList.value, word];
       runStep();
     };
-
-    const getNode = (index) => {
+    const getNode = (index: number) => {
       const query = Taro.createSelectorQuery();
       setTimeout(() => {
         let width = 100;
@@ -106,36 +113,49 @@ export default create({
         });
         query
           .select('.dmitem' + index)
-          .boundingClientRect((recs: any) => {
+          .boundingClientRect((recs) => {
             let height = recs.height;
             let nodeTop = (index % rows.value) * (height + top.value) + 20 + 'px';
             styleInfo(index, nodeTop, width);
           })
           .exec();
-        // let ele = document.getElementsByClassName('dmitem'+index)[0];
-        // let transitionFlag = false;
-        // ele.addEventListener('animationend', (e:any) => {
-        //   if(e.target.id === e.currentTarget.id && transitionFlag) {
-        //     transitionFlag = false;
-        //     // deleteNode(index)
-        //   }else {
-        //     transitionFlag = true;
-        //   }
-        // }, false);
       }, 500);
     };
 
     const runStep = () => {
-      danmuList.value.forEach((item, index) => {
-        getNode(index);
+      danmuList.value.forEach((item, index: number) => {
+        let el = danmuList.value[index]?.el;
+        if (!el) {
+          danmuListSlots.value.push(item);
+          let l = slotDefault ? String(danmuList.value.length) : '';
+          let s = l + danmuListSlots.value.indexOf(item);
+          getNode(Number(s));
+        } else {
+          if (el?.classList.contains('dmitem')) {
+            el.classList.remove('dmitem');
+          }
+          if (el?.classList.contains('dmitem' + index)) {
+            el.classList.remove('dmitem' + index);
+          }
+          if (slotDefault && el) {
+            if (el?.classList.contains('move')) {
+              el.classList.remove('move');
+            }
+            el.classList.add('.move');
+          }
+          el.classList.add('.dmitem .dmitem' + index);
+          getNode(index);
+        }
       });
     };
-    let styleList = reactive([]);
-    const styleInfo = (index, nodeTop, width) => {
-      let n = Math.floor(Math.random() * (10 - 5)) + 5;
+    const distance = ref('0');
+    let styleList: any[] = reactive([]);
+    const styleInfo = (index: number, nodeTop: string, width: number) => {
+      // let n = Math.floor(Math.random() * (10 - 5)) + 5;
       let timeIndex = index - rows.value > 0 ? index - rows.value : 0;
       let list = styleList;
       let time = list[timeIndex] ? Number(list[timeIndex]['--time']) : 0;
+      distance.value = '-' + (speeds / 1000) * 200 + '%';
 
       let obj = {
         top: nodeTop,
@@ -145,10 +165,34 @@ export default create({
         animationDelay: `${props.frequency * index + time}ms`,
         '--move-distance': `-${width}px`
       };
-      styleList.push(obj);
+      if (slotDefault && danmuList.value[index]?.el) {
+        let orginalSty = danmuList.value[index].el.style;
+        danmuList.value[index].el.style = Object.assign(orginalSty, obj);
+      } else {
+        styleList.push(obj);
+      }
     };
 
-    return { classes, danmuList, add, styleList };
+    return { classes, danmuList, add, styleList, distance, danmuListSlots };
   }
 });
 </script>
+
+<style lang="scss">
+@keyframes moving {
+  from {
+    transform: translateX(100%);
+  }
+  to {
+    transform: translateX(v-bind('distance'));
+  }
+}
+@-webkit-keyframes moving {
+  from {
+    -webkit-transform: translateX(100%);
+  }
+  to {
+    transform: translateX(v-bind('distance'));
+  }
+}
+</style>

+ 76 - 27
src/packages/__VUE/barrage/index.vue

@@ -1,13 +1,13 @@
 <template>
-  <view ref="dmBody" :class="classes">
-    <view ref="dmContainer" class="dmContainer"></view>
-    <!-- <view v-for="(item, index) of danmuList" :key="'danmu'+index" class="dmitem">
-      {{item}}
-    </view> -->
-  </view>
+  <div ref="dmBody" :class="classes">
+    <div ref="dmContainer" class="dmContainer slotContainer" v-if="$slots.default">
+      <slot></slot>
+    </div>
+    <div ref="dmContainer" class="dmContainer" v-else></div>
+  </div>
 </template>
 <script lang="ts">
-import { computed, onMounted, onUnmounted, onDeactivated, ref, reactive, toRefs, watch, nextTick } from 'vue';
+import { computed, onMounted, onUnmounted, onDeactivated, ref, watch, nextTick, useSlots } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create } = createComponent('barrage');
 
@@ -23,7 +23,7 @@ export default create({
     },
     speeds: {
       type: Number,
-      default: 2000
+      default: 5000
     },
     rows: {
       type: Number,
@@ -40,7 +40,9 @@ export default create({
   },
   emits: ['click'],
 
-  setup(props, { emit }) {
+  setup(props, { slots }) {
+    const slotDefault = !!useSlots().default;
+
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
@@ -51,8 +53,8 @@ export default create({
     let dmBody = ref<HTMLDivElement>(document.createElement('div'));
     let dmContainer = ref<HTMLDivElement>(document.createElement('div'));
 
-    let timer: number = 0;
-    const danmuList = ref<any[]>(props.danmu);
+    let timer = 0;
+    const danmuList: any = ref(props.danmu);
     const rows = ref<number>(props.rows);
     const top = ref<number>(props.top);
     const index = ref<number>(0);
@@ -61,7 +63,12 @@ export default create({
 
     onMounted(() => {
       danmuCWidth.value = dmBody.value.offsetWidth;
-      run();
+      if (slotDefault) {
+        danmuList.value = slots?.default?.();
+        run();
+      } else {
+        run();
+      }
     });
 
     onUnmounted(() => {
@@ -76,8 +83,10 @@ export default create({
 
     watch(
       () => props.danmu,
-      (newValue, oldVlaue) => {
-        danmuList.value = [...newValue];
+      (newValue) => {
+        if (props.danmu.length > 0) {
+          danmuList.value = [...newValue];
+        }
       }
     );
 
@@ -98,34 +107,74 @@ export default create({
         run();
       }, props.frequency);
     };
-
+    const distance = ref('0');
     const play = () => {
       if (!props.loop && index.value >= danmuList.value.length) {
         return;
       }
       const _index = props.loop ? index.value % danmuList.value.length : index.value;
-      let el = document.createElement(`view`);
-      el.innerHTML = danmuList.value[_index] as string;
-      el.classList.add('dmitem');
-      dmContainer.value.appendChild(el);
-
+      let el = document.createElement(`div`);
+      if (slotDefault && danmuList.value[_index]?.el) {
+        el = danmuList.value[_index]?.el;
+        if (el?.classList.contains('dmitem')) {
+          el.classList.remove('dmitem');
+        }
+        if (el?.classList.contains('move')) {
+          el.classList.remove('move');
+        }
+        el?.classList.add('dmitem');
+      } else {
+        el.innerHTML = danmuList.value[_index] as string;
+        el.classList.add('dmitem');
+        dmContainer.value.appendChild(el);
+      }
+      // let el = document.createElement(`div`);
+      // el.innerHTML = danmuList.value[_index] as string;
+      // el.classList.add('dmitem');
+      // dmContainer.value.appendChild(el);
       nextTick(() => {
-        const width = el.offsetWidth;
         const height = el.offsetHeight;
         el.classList.add('move');
         el.style.animationDuration = `${speeds}ms`;
         el.style.top = (_index % rows.value) * (height + top.value) + 20 + 'px';
-        el.style.width = width + 20 + 'px';
+        if (!slotDefault) {
+          const width = el.offsetWidth;
+          el.style.width = width + 20 + 'px';
+        }
         // el.style.left = "-"+(_index % rows.value) + 'px';
         el.style.setProperty('--move-distance', `-${danmuCWidth.value}px`);
+        distance.value = '-' + (speeds / 1000) * 150 + '%';
         el.dataset.index = `${_index}`;
-        el.addEventListener('animationend', () => {
-          dmContainer.value.removeChild(el);
-        });
-        index.value++;
+        if (slotDefault) {
+          index.value++;
+        } else {
+          el.addEventListener('animationend', () => {
+            dmContainer.value.removeChild(el);
+          });
+          index.value++;
+        }
       });
     };
-    return { classes, danmuList, dmBody, dmContainer, add };
+    return { classes, danmuList, dmBody, dmContainer, add, distance };
   }
 });
 </script>
+
+<style lang="scss">
+@keyframes moving {
+  from {
+    transform: translateX(100%);
+  }
+  to {
+    transform: translateX(v-bind('distance'));
+  }
+}
+@-webkit-keyframes moving {
+  from {
+    -webkit-transform: translateX(100%);
+  }
+  to {
+    transform: translateX(v-bind('distance'));
+  }
+}
+</style>

+ 9 - 0
src/sites/mobile-taro/vue/src/business/pages/barrage/index.vue

@@ -4,6 +4,15 @@
     <nut-cell>
       <nut-barrage ref="danmu" :danmu="list"></nut-barrage>
     </nut-cell>
+    <h2>slot 用法</h2>
+    <nut-cell>
+      <nut-barrage ref="danmu">
+        <span>aaa</span>
+        <span>bbb</span>
+        <span>ccc</span>
+        <span>ddd</span>
+      </nut-barrage>
+    </nut-cell>
     <div class="test">
       <button @click="addDanmu" class="add nut-button--primary">随机添加</button>
     </div>