wyb-noticeBar.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <template>
  2. <view class="container" v-if="show"
  3. :style="{
  4. width: rpxWidth + 'rpx',
  5. height: height + 'rpx',
  6. backgroundColor: bgColor || autoBgColor,
  7. border: hasBorder ? '1px solid' + color : 'none'}">
  8. <view class="close-box" v-if="showClose" @tap="show = false"
  9. :style="{
  10. width: autoCloseWidth + 'px',
  11. height: height + 'rpx',
  12. paddingLeft: showIcon ? '10rpx' : '0',
  13. backgroundColor: bgColor || autoBgColor}">
  14. <view class="iconfont icon-close" :style="{
  15. fontSize: autoCloseSize,
  16. color: color,
  17. lineHeight: height + 'rpx'}" />
  18. </view>
  19. <view class="notice-box" v-if="showIcon"
  20. :style="{
  21. width: autoNoticeWidth + 'px',
  22. height: height + 'rpx',
  23. backgroundColor: bgColor || autoBgColor}">
  24. <view class="iconfont icon-tongzhi"
  25. :style="{
  26. fontSize: autoNoticeSize,
  27. color: color,
  28. lineHeight: height + 'rpx'}" />
  29. </view>
  30. <view class="marquee-hori" v-if="type==='hori-connect'" @tap="showMoreExtendTap"
  31. :style="{
  32. width: autoMarQueeWidth + 'px',
  33. height: '105%',
  34. backgroundColor: bgColor || autoBgColor}">
  35. <view class="box-hori"
  36. :style="{
  37. width: autoBoxWidth + 'px',
  38. animationName: scroll ? '' : 'none',
  39. animationDuration: animDur}">
  40. <text id="text"
  41. :style="{
  42. whiteSpace: 'pre',
  43. color: color,
  44. fontWeight: fontWeight,
  45. fontSize: fontSize + 'rpx',
  46. lineHeight: height + 'rpx'}">{{text.length<=1 ? text[0] : text.join(join)}}</text>
  47. <view :style="'width: ' + blockWidth + 'px; height: 100%'" />
  48. <text
  49. :style="{
  50. whiteSpace: 'pre',
  51. color: color,
  52. fontWeight: fontWeight,
  53. fontSize: fontSize + 'rpx',
  54. lineHeight: height + 'rpx'}">{{text.length<=1 ? text[0] : text.join(join)}}</text>
  55. <view :style="'width: ' + blockWidth + 'px; height: 100%'" />
  56. </view>
  57. </view>
  58. <view class="marquee-vert" v-if="type==='vert' || type === 'hori-break'" @tap="showMoreExtendTap"
  59. :style="{
  60. width: autoMarQueeWidth + 'px',
  61. height: '100%',
  62. backgroundColor: bgColor || autoBgColor}">
  63. <view class="box-vert">
  64. <swiper
  65. class="swiper"
  66. :style="{height: fontSize * 1.3 + 'rpx'}"
  67. :autoplay="scroll"
  68. :interval="time"
  69. :duration="duration"
  70. :vertical="type === 'vert'"
  71. :circular="true"
  72. :touchable="false"
  73. :disable-touch="true"
  74. @animationfinish="swpChange">
  75. <swiper-item
  76. class="swiper-item"
  77. v-for="(item,index) in text" :key="index"
  78. v-if="text.length <= 2">
  79. <text :style="{
  80. whiteSpace: 'pre',
  81. color: color,
  82. fontWeight: fontWeight,
  83. fontSize: fontSize + 'rpx'}">{{item}}</text>
  84. </swiper-item>
  85. <swiper-item v-if="text.length > 2" class="swiper-item">
  86. <text :style="{
  87. whiteSpace: 'pre',
  88. color: color,
  89. fontWeight: fontWeight,
  90. fontSize: fontSize + 'rpx'}">{{swp[0]}}</text>
  91. </swiper-item>
  92. <swiper-item v-if="text.length > 2" class="swiper-item">
  93. <text :style="{
  94. whiteSpace: 'pre',
  95. color: color,
  96. fontWeight: fontWeight,
  97. fontSize: fontSize + 'rpx'}">{{swp[1]}}</text>
  98. </swiper-item>
  99. </swiper>
  100. </view>
  101. </view>
  102. <view class="look-more-box" v-if="showMore" @tap="showMoreTap" :style="{
  103. width: autoMoreWidth + 'px',
  104. height: height + 'rpx',
  105. backgroundColor: bgColor || autoBgColor}">
  106. <view class="iconfont icon-right" :style="{
  107. fontSize: autoMoreSize,
  108. color: color,
  109. lineHeight: height + 'rpx'}" />
  110. </view>
  111. </view>
  112. </template>
  113. <script>
  114. export default {
  115. data() {
  116. return {
  117. show: true,
  118. animDur: '5s',
  119. autoBoxWidth: 0,
  120. autoBoxHeight: 0,
  121. textPercent: 0.77,
  122. noticePercent: 0.075,
  123. morePercent: 0.09,
  124. closePercent: 0.065,
  125. swp: this.text.slice(),
  126. textIdx: 0,
  127. }
  128. },
  129. computed: {
  130. rpxWidth() {
  131. return parseFloat(this.width) / uni.getSystemInfoSync().screenWidth * 750
  132. },
  133. autoMarQueeWidth() {
  134. let percent = this.textPercent
  135. if (!this.showClose) {
  136. percent += this.closePercent
  137. }
  138. if (!this.showIcon) {
  139. percent += this.noticePercent
  140. }
  141. if (!this.showMore) {
  142. percent += this.morePercent
  143. }
  144. return parseFloat(this.width) * percent
  145. },
  146. autoNoticeWidth() {
  147. return parseFloat(this.width) * this.noticePercent
  148. },
  149. autoMoreWidth() {
  150. return parseFloat(this.width) * this.morePercent
  151. },
  152. autoCloseWidth() {
  153. return parseFloat(this.width) * this.closePercent
  154. },
  155. blockWidth() {
  156. let result = 0
  157. let eleWidth = 0
  158. this.getRect('#text').then(res => {
  159. eleWidth = res.width
  160. })
  161. let comWidth = parseFloat(this.autoMarQueeWidth)
  162. result = comWidth - parseFloat(eleWidth) - (this.spaceConst)
  163. return result
  164. },
  165. autoBgColor() {
  166. return this.RGBChange(this.color, 0.85, 'light')
  167. },
  168. autoNoticeSize() {
  169. return parseFloat(this.width) * 0.087 + 'rpx'
  170. },
  171. autoMoreSize() {
  172. return parseFloat(this.width) * 0.087 + 'rpx'
  173. },
  174. autoCloseSize() {
  175. return parseFloat(this.width) * 0.087 + 'rpx'
  176. }
  177. },
  178. props: {
  179. // 整体配置参数
  180. type: {
  181. type: String,
  182. default: 'hori-connect'
  183. },
  184. width: {
  185. type: [String, Number],
  186. default: uni.getSystemInfoSync().screenWidth
  187. },
  188. height: {
  189. type: [String, Number],
  190. default: 70
  191. },
  192. color: {
  193. type: String,
  194. default: '#f5a300'
  195. },
  196. bgColor: {
  197. type: String,
  198. default: ''
  199. },
  200. text: {
  201. type: Array,
  202. default () {
  203. return []
  204. }
  205. },
  206. fontWeight: {
  207. type: String,
  208. default: 'normal'
  209. },
  210. fontSize: {
  211. type: [String, Number],
  212. default: '27'
  213. },
  214. hasBorder: {
  215. type: Boolean,
  216. default: false,
  217. },
  218. scroll: {
  219. type: Boolean,
  220. default: true,
  221. },
  222. showIcon: {
  223. type: Boolean,
  224. default: true
  225. },
  226. showMore: {
  227. type: Boolean,
  228. default: true
  229. },
  230. showClose: {
  231. type: Boolean,
  232. default: false
  233. },
  234. url: {
  235. type: String,
  236. default: ''
  237. },
  238. extendMoreArea: {
  239. type: Boolean,
  240. default: false
  241. },
  242. // hori-connect配置参数
  243. join: {
  244. type: String,
  245. default: ' '
  246. },
  247. spaceConst: {
  248. type: Number,
  249. default: 0
  250. },
  251. speed: {
  252. type: Number,
  253. default: 40
  254. },
  255. // vert和hori-break配置参数
  256. time: {
  257. type: Number,
  258. default: 3000
  259. },
  260. duration: {
  261. type: Number,
  262. default: 1000
  263. }
  264. },
  265. mounted() {
  266. this.getRect('#text').then(res => {
  267. this.autoBoxWidth = (res.width + this.blockWidth) * 2
  268. this.animDur = parseFloat(res.width + this.blockWidth) / this.speed + 's'
  269. })
  270. },
  271. methods: {
  272. showMoreTap() {
  273. if (this.url) {
  274. uni.navigateTo({
  275. url: this.url,
  276. fail(msg) {
  277. console.log(msg)
  278. }
  279. })
  280. } else {
  281. this.$emit('showMore')
  282. }
  283. },
  284. showMoreExtendTap() {
  285. if (this.extendMoreArea) {
  286. this.showMoreTap()
  287. }
  288. },
  289. swpChange(e) {
  290. if (this.text.length > 2) {
  291. let current = e.detail.current
  292. if (current === 1) {
  293. this.swp.splice(0, 1, this.swp[2])
  294. this.swp.splice(2, 1)
  295. } else if (current === 0) {
  296. this.swp.splice(1, 1, this.swp[2])
  297. this.swp.splice(2, 1)
  298. }
  299. this.swp.push(this.text[this.textIdx])
  300. this.textIdx++
  301. if (this.textIdx === this.text.length - 1) this.textIdx = 0
  302. }
  303. },
  304. getRect(selector) {
  305. return new Promise(resolve => {
  306. uni.createSelectorQuery().in(this)['select'](selector).boundingClientRect(rect => {
  307. if (rect) resolve(rect)
  308. }).exec()
  309. })
  310. },
  311. RGBChange(color, level, type) {
  312. // hex转rgb
  313. if (color.length === 4) {
  314. let arr = color.split('')
  315. color = '#' + arr[1] + arr[1] + arr[2] + arr[2] + arr[3] + arr[3]
  316. }
  317. let color16List = [color.substring(1, 3), color.substring(3, 5), color.substring(5, 7)]
  318. let r = parseInt(color16List[0], 16)
  319. let g = parseInt(color16List[1], 16)
  320. let b = parseInt(color16List[2], 16)
  321. let rgbc = [r, g, b]
  322. // 减淡或加深
  323. for (var i = 0; i < 3; i++)
  324. type === 'light' ? rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]) : rgbc[i] = Math.floor(rgbc[i] * (1 -
  325. level))
  326. // rgb转hex
  327. let R = rgbc[0].toString(16)
  328. let G = rgbc[1].toString(16)
  329. let B = rgbc[2].toString(16)
  330. if (R.length === 1) R = '0' + R
  331. if (G.length === 1) G = '0' + G
  332. if (B.length === 1) B = '0' + B
  333. return '#' + R + G + B
  334. }
  335. }
  336. }
  337. </script>
  338. <style>
  339. @import "./iconfont.css";
  340. @keyframes hori-animation {
  341. 0% {
  342. transform-origin: left;
  343. transform: translateX(0);
  344. }
  345. 100% {
  346. transform-origin: left;
  347. transform: translateX(-50%);
  348. }
  349. }
  350. .base {
  351. }
  352. .container {
  353. display: flex;
  354. flex-direction: row;
  355. align-items: center;
  356. justify-content: space-around;
  357. overflow: hidden;
  358. }
  359. .marquee-hori,
  360. .marquee-vert{
  361. overflow: hidden;
  362. white-space: nowrap;
  363. text-overflow: clip;
  364. position: relative;
  365. }
  366. .marquee-vert {
  367. display: flex;
  368. flex-direction: column;
  369. align-items: flex-start;
  370. justify-content: center;
  371. }
  372. .box-hori {
  373. height: 100%;
  374. display: flex;
  375. flex-direction: row;
  376. animation-name: hori-animation;
  377. animation-duration: 5s;
  378. animation-timing-function: linear;
  379. animation-iteration-count: infinite;
  380. animation-delay: 1s;
  381. white-space: nowrap;
  382. }
  383. .box-vert {
  384. width: 100%;
  385. padding-bottom: 4rpx;
  386. display: flex;
  387. flex-direction: column;
  388. white-space: nowrap;
  389. }
  390. .swiper {
  391. display: flex;
  392. flex-direction: column;
  393. align-items: flex-start;
  394. justify-content: center;
  395. }
  396. .swiper-item {
  397. overflow: hidden;
  398. display: flex;
  399. flex-direction: column;
  400. align-items: flex-start;
  401. justify-content: center;
  402. }
  403. .close-box {
  404. display: flex;
  405. flex-direction: row;
  406. align-items: center;
  407. justify-content: center;
  408. box-sizing: border-box;
  409. overflow: hidden;
  410. }
  411. .notice-box {
  412. display: flex;
  413. flex-direction: row;
  414. align-items: center;
  415. justify-content: flex-start;
  416. box-sizing: border-box;
  417. overflow: hidden;
  418. padding-left: 15rpx;
  419. }
  420. .look-more-box {
  421. display: flex;
  422. flex-direction: row;
  423. align-items: center;
  424. justify-content: center;
  425. box-sizing: border-box;
  426. overflow: hidden;
  427. }
  428. </style>