SgyMarquee.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <template>
  2. <div class="sgy-marquee" :data-guid="guid">
  3. <p :class="myClass">
  4. <template v-if="$slots.default">
  5. <i class="real-text"><slot></slot></i>
  6. <i class="text" :style="`visibility: ${isMarquee ? 'visible': 'hidden'}`">
  7. {{this.$slots.default[0].text}}
  8. </i>
  9. </template>
  10. <template v-else>
  11. <i v-html="html"></i><i class="text" :style="`visibility: ${isMarquee ? 'visible': 'hidden'}`" v-html="html"></i>
  12. </template>
  13. </p>
  14. </div>
  15. </template>
  16. <script>
  17. export default {
  18. components: {},
  19. props: {
  20. hover: {
  21. type: Boolean,
  22. default: false
  23. },
  24. html: {
  25. type: String,
  26. default: ""
  27. }
  28. },
  29. data() {
  30. return {
  31. guid: "",
  32. textWidth: 0,
  33. offsetWidth: 0
  34. };
  35. },
  36. computed: {
  37. isMarquee() {
  38. return (this.textWidth - 80) / 2 > this.offsetWidth;
  39. },
  40. myClass() {
  41. if (this.isMarquee) {
  42. return this.hover ? "is-hover-marquee" : "is-marquee";
  43. } else {
  44. return "";
  45. }
  46. }
  47. },
  48. mounted() {
  49. this.init();
  50. },
  51. methods: {
  52. init() {
  53. // 避免样式覆盖
  54. this.guid = this.guidFunc();
  55. this.$nextTick(() => {
  56. this.textWidth = document.querySelector(
  57. `.sgy-marquee[data-guid="${this.guid}"]`
  58. ).scrollWidth;
  59. this.offsetWidth = document.querySelector(
  60. `.sgy-marquee[data-guid="${this.guid}"]`
  61. ).offsetWidth;
  62. this.initCss();
  63. });
  64. },
  65. guidFunc() {
  66. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(
  67. c
  68. ) {
  69. let r = (Math.random() * 16) | 0;
  70. let v = c === "x" ? r : (r & 0x3) | 0x8;
  71. return v.toString(16);
  72. });
  73. },
  74. initCss() {
  75. let cssText = `
  76. .sgy-marquee[data-guid="${this.guid}"] .is-marquee {
  77. animation: marquee-${this.guid} ${this.textWidth /
  78. 200}s linear infinite;
  79. }
  80. .sgy-marquee[data-guid="${this.guid}"] .is-hover-marquee:hover {
  81. animation: marquee-${this.guid} ${this.textWidth /
  82. 200}s linear infinite;
  83. }
  84. @keyframes marquee-${this.guid} {
  85. 0% {
  86. transform: translateX(0px);
  87. }
  88. 100% {
  89. transform: translateX(${-this.textWidth / 2 - 40}px);
  90. }
  91. }`;
  92. this.insertCss(cssText);
  93. },
  94. insertCss(cssText) {
  95. let head = document.head || document.getElementsByTagName("head")[0];
  96. let style = document.createElement("style");
  97. style.type = "text/css";
  98. let textNode = document.createTextNode(cssText);
  99. style.appendChild(textNode);
  100. head.appendChild(style);
  101. }
  102. }
  103. };
  104. </script>
  105. <style scoped lang="less" style="text/less">
  106. .sgy-marquee {
  107. width: 100%;
  108. overflow: hidden;
  109. white-space: nowrap;
  110. > p {
  111. display: inline-block;
  112. }
  113. .text {
  114. padding-left: 80px;
  115. }
  116. }
  117. </style>