uni-notice-bar.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. <template>
  2. <view
  3. v-if="show"
  4. class="uni-noticebar"
  5. :style="'background-color:' + backgroundColor + ';width: 100%'"
  6. @click="onClick"
  7. >
  8. <!-- <uni-icons v-if="showIcon === true || showIcon === 'true'" class="uni-noticebar-icon" type="sound"
  9. :color="color" size="22" /> -->
  10. <view
  11. ref="textBox"
  12. class="uni-noticebar__content-wrapper"
  13. :class="{
  14. 'uni-noticebar__content-wrapper--scrollable': scrollable,
  15. 'uni-noticebar__content-wrapper--single':
  16. !scrollable && (single || moreText),
  17. }"
  18. >
  19. <view
  20. :id="elIdBox"
  21. class="uni-noticebar__content"
  22. :class="{
  23. 'uni-noticebar__content--scrollable': scrollable,
  24. 'uni-noticebar__content--single': !scrollable && (single || moreText),
  25. }"
  26. >
  27. <text
  28. :id="elId"
  29. ref="animationEle"
  30. class="uni-noticebar__content-text"
  31. :class="{
  32. 'uni-noticebar__content-text--scrollable': scrollable,
  33. 'uni-noticebar__content-text--single':
  34. !scrollable && (single || showGetMore),
  35. }"
  36. :style="{
  37. color: color,
  38. width: wrapWidth + 'px',
  39. animationDuration: animationDuration,
  40. '-webkit-animationDuration': animationDuration,
  41. animationPlayState: webviewHide ? 'paused' : animationPlayState,
  42. '-webkit-animationPlayState': webviewHide
  43. ? 'paused'
  44. : animationPlayState,
  45. animationDelay: animationDelay,
  46. '-webkit-animationDelay': animationDelay,
  47. }"
  48. >{{ text }}</text
  49. >
  50. </view>
  51. </view>
  52. <view
  53. v-if="showGetMore === true || showGetMore === 'true'"
  54. class="uni-noticebar__more uni-cursor-point"
  55. @click="clickMore"
  56. >
  57. <text
  58. v-if="moreText.length > 0"
  59. :style="{ color: moreColor }"
  60. class="uni-noticebar__more-text"
  61. >{{ moreText }}</text
  62. >
  63. <!-- <uni-icons v-else type="right" :color="moreColor" size="16" /> -->
  64. </view>
  65. <view
  66. class="uni-noticebar-close uni-cursor-point"
  67. v-if="
  68. (showClose === true || showClose === 'true') &&
  69. (showGetMore === false || showGetMore === 'false')
  70. "
  71. >
  72. <!-- <uni-icons
  73. type="closeempty" :color="color" size="16" @click="close" /> -->
  74. </view>
  75. </view>
  76. </template>
  77. <script>
  78. // #ifdef APP-NVUE
  79. const dom = weex.requireModule("dom");
  80. const animation = weex.requireModule("animation");
  81. // #endif
  82. /**
  83. * NoticeBar 自定义导航栏
  84. * @description 通告栏组件
  85. * @tutorial https://ext.dcloud.net.cn/plugin?id=30
  86. * @property {Number} speed 文字滚动的速度,默认100px/秒
  87. * @property {String} text 显示文字
  88. * @property {String} backgroundColor 背景颜色
  89. * @property {String} color 文字颜色
  90. * @property {String} moreColor 查看更多文字的颜色
  91. * @property {String} moreText 设置“查看更多”的文本
  92. * @property {Boolean} single = [true|false] 是否单行
  93. * @property {Boolean} scrollable = [true|false] 是否滚动,为true时,NoticeBar为单行
  94. * @property {Boolean} showIcon = [true|false] 是否显示左侧喇叭图标
  95. * @property {Boolean} showClose = [true|false] 是否显示左侧关闭按钮
  96. * @property {Boolean} showGetMore = [true|false] 是否显示右侧查看更多图标,为true时,NoticeBar为单行
  97. * @event {Function} click 点击 NoticeBar 触发事件
  98. * @event {Function} close 关闭 NoticeBar 触发事件
  99. * @event {Function} getmore 点击”查看更多“时触发事件
  100. */
  101. export default {
  102. name: "UniNoticeBar",
  103. emits: ["click", "getmore", "close"],
  104. props: {
  105. prConfig: {
  106. type: Number,
  107. default: 0,
  108. },
  109. text: {
  110. type: String,
  111. default: "",
  112. },
  113. moreText: {
  114. type: String,
  115. default: "",
  116. },
  117. backgroundColor: {
  118. type: String,
  119. default: "#FFF9EA",
  120. },
  121. speed: {
  122. // 默认1s滚动100px
  123. type: Number,
  124. default: 100,
  125. },
  126. color: {
  127. type: String,
  128. default: "#FF9A43",
  129. },
  130. moreColor: {
  131. type: String,
  132. default: "#FF9A43",
  133. },
  134. single: {
  135. // 是否单行
  136. type: [Boolean, String],
  137. default: false,
  138. },
  139. scrollable: {
  140. // 是否滚动,添加后控制单行效果取消
  141. type: [Boolean, String],
  142. default: false,
  143. },
  144. showIcon: {
  145. // 是否显示左侧icon
  146. type: [Boolean, String],
  147. default: false,
  148. },
  149. showGetMore: {
  150. // 是否显示右侧查看更多
  151. type: [Boolean, String],
  152. default: false,
  153. },
  154. showClose: {
  155. // 是否显示左侧关闭按钮
  156. type: [Boolean, String],
  157. default: false,
  158. },
  159. },
  160. data() {
  161. const elId = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`;
  162. const elIdBox = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`;
  163. return {
  164. textWidth: 0,
  165. boxWidth: 0,
  166. wrapWidth: "",
  167. webviewHide: false,
  168. // #ifdef APP-NVUE
  169. stopAnimation: false,
  170. // #endif
  171. elId: elId,
  172. elIdBox: elIdBox,
  173. show: true,
  174. animationDuration: "none",
  175. animationPlayState: "paused",
  176. animationDelay: "0s",
  177. };
  178. },
  179. mounted() {
  180. // #ifdef APP-PLUS
  181. var pages = getCurrentPages();
  182. var page = pages[pages.length - 1];
  183. var currentWebview = page.$getAppWebview();
  184. currentWebview.addEventListener("hide", () => {
  185. this.webviewHide = true;
  186. });
  187. currentWebview.addEventListener("show", () => {
  188. this.webviewHide = false;
  189. });
  190. // #endif
  191. this.$nextTick(() => {
  192. this.initSize();
  193. });
  194. },
  195. // #ifdef APP-NVUE
  196. beforeDestroy() {
  197. this.stopAnimation = true;
  198. },
  199. // #endif
  200. methods: {
  201. initSize() {
  202. if (this.scrollable) {
  203. // #ifndef APP-NVUE
  204. let query = [],
  205. boxWidth = 0,
  206. textWidth = 0;
  207. let textQuery = new Promise((resolve, reject) => {
  208. uni
  209. .createSelectorQuery()
  210. // #ifndef MP-ALIPAY
  211. .in(this)
  212. // #endif
  213. .select(`#${this.elId}`)
  214. .boundingClientRect()
  215. .exec((ret) => {
  216. this.textWidth = ret[0].width;
  217. resolve();
  218. });
  219. });
  220. let boxQuery = new Promise((resolve, reject) => {
  221. uni
  222. .createSelectorQuery()
  223. // #ifndef MP-ALIPAY
  224. .in(this)
  225. // #endif
  226. .select(`#${this.elIdBox}`)
  227. .boundingClientRect()
  228. .exec((ret) => {
  229. this.boxWidth = ret[0].width;
  230. resolve();
  231. });
  232. });
  233. query.push(textQuery);
  234. query.push(boxQuery);
  235. Promise.all(query).then(() => {
  236. this.animationDuration = `${this.textWidth / this.speed}s`;
  237. this.animationDelay = `-${this.boxWidth / this.speed}s`;
  238. setTimeout(() => {
  239. this.animationPlayState = "running";
  240. }, 1000);
  241. });
  242. // #endif
  243. // #ifdef APP-NVUE
  244. dom.getComponentRect(this.$refs["animationEle"], (res) => {
  245. let winWidth = uni.getWindowInfo().windowWidth;
  246. this.textWidth = res.size.width;
  247. animation.transition(
  248. this.$refs["animationEle"],
  249. {
  250. styles: {
  251. transform: `translateX(-${winWidth}px)`,
  252. },
  253. duration: 0,
  254. timingFunction: "linear",
  255. delay: 0,
  256. },
  257. () => {
  258. if (!this.stopAnimation) {
  259. animation.transition(
  260. this.$refs["animationEle"],
  261. {
  262. styles: {
  263. transform: `translateX(-${this.textWidth}px)`,
  264. },
  265. timingFunction: "linear",
  266. duration: ((this.textWidth - winWidth) / this.speed) * 1000,
  267. delay: 1000,
  268. },
  269. () => {
  270. if (!this.stopAnimation) {
  271. this.loopAnimation();
  272. }
  273. }
  274. );
  275. }
  276. }
  277. );
  278. });
  279. // #endif
  280. }
  281. // #ifdef APP-NVUE
  282. if (!this.scrollable && (this.single || this.moreText)) {
  283. dom.getComponentRect(this.$refs["textBox"], (res) => {
  284. this.wrapWidth = res.size.width;
  285. });
  286. }
  287. // #endif
  288. },
  289. loopAnimation() {
  290. // #ifdef APP-NVUE
  291. animation.transition(
  292. this.$refs["animationEle"],
  293. {
  294. styles: {
  295. transform: `translateX(0px)`,
  296. },
  297. duration: 0,
  298. },
  299. () => {
  300. if (!this.stopAnimation) {
  301. animation.transition(
  302. this.$refs["animationEle"],
  303. {
  304. styles: {
  305. transform: `translateX(-${this.textWidth}px)`,
  306. },
  307. duration: (this.textWidth / this.speed) * 1000,
  308. timingFunction: "linear",
  309. delay: 0,
  310. },
  311. () => {
  312. if (!this.stopAnimation) {
  313. this.loopAnimation();
  314. }
  315. }
  316. );
  317. }
  318. }
  319. );
  320. // #endif
  321. },
  322. clickMore() {
  323. this.$emit("getmore");
  324. },
  325. close() {
  326. this.show = false;
  327. this.$emit("close");
  328. },
  329. onClick() {
  330. this.$emit("click");
  331. },
  332. },
  333. };
  334. </script>
  335. <style lang="scss" scoped>
  336. .uni-noticebar {
  337. /* #ifndef APP-NVUE */
  338. display: flex;
  339. width: 100%;
  340. box-sizing: border-box;
  341. /* #endif */
  342. flex-direction: row;
  343. align-items: center;
  344. width: 500rpx;
  345. }
  346. .uni-cursor-point {
  347. /* #ifdef H5 */
  348. cursor: pointer;
  349. /* #endif */
  350. }
  351. .uni-noticebar-close {
  352. margin-left: 8px;
  353. margin-right: 5px;
  354. }
  355. .uni-noticebar-icon {
  356. margin-right: 5px;
  357. }
  358. .uni-noticebar__content-wrapper {
  359. flex: 1;
  360. flex-direction: column;
  361. overflow: hidden;
  362. }
  363. .uni-noticebar__content-wrapper--single {
  364. /* #ifndef APP-NVUE */
  365. line-height: 18px;
  366. /* #endif */
  367. }
  368. .uni-noticebar__content-wrapper--single,
  369. .uni-noticebar__content-wrapper--scrollable {
  370. flex-direction: row;
  371. }
  372. /* #ifndef APP-NVUE */
  373. .uni-noticebar__content-wrapper--scrollable {
  374. position: relative;
  375. height: 18px;
  376. }
  377. /* #endif */
  378. .uni-noticebar__content--scrollable {
  379. /* #ifdef APP-NVUE */
  380. flex: 0;
  381. /* #endif */
  382. /* #ifndef APP-NVUE */
  383. flex: 1;
  384. display: block;
  385. overflow: hidden;
  386. /* #endif */
  387. }
  388. .uni-noticebar__content--single {
  389. /* #ifndef APP-NVUE */
  390. display: flex;
  391. flex: none;
  392. width: 100%;
  393. justify-content: center;
  394. /* #endif */
  395. }
  396. .uni-noticebar__content-text {
  397. font-size: 14px;
  398. line-height: 18px;
  399. /* #ifndef APP-NVUE */
  400. word-break: break-all;
  401. /* #endif */
  402. }
  403. .uni-noticebar__content-text--single {
  404. /* #ifdef APP-NVUE */
  405. lines: 1;
  406. /* #endif */
  407. /* #ifndef APP-NVUE */
  408. display: block;
  409. width: 100%;
  410. white-space: nowrap;
  411. /* #endif */
  412. overflow: hidden;
  413. text-overflow: ellipsis;
  414. }
  415. .uni-noticebar__content-text--scrollable {
  416. /* #ifdef APP-NVUE */
  417. lines: 1;
  418. padding-left: 750rpx;
  419. /* #endif */
  420. /* #ifndef APP-NVUE */
  421. position: absolute;
  422. display: block;
  423. height: 18px;
  424. line-height: 18px;
  425. white-space: nowrap;
  426. padding-left: 100%;
  427. animation: notice 10s 0s linear infinite both;
  428. animation-play-state: paused;
  429. /* #endif */
  430. }
  431. .uni-noticebar__more {
  432. /* #ifndef APP-NVUE */
  433. display: inline-flex;
  434. /* #endif */
  435. flex-direction: row;
  436. flex-wrap: nowrap;
  437. align-items: center;
  438. padding-left: 5px;
  439. }
  440. .uni-noticebar__more-text {
  441. font-size: 14px;
  442. }
  443. @keyframes notice {
  444. 100% {
  445. transform: translate3d(-100%, 0, 0);
  446. }
  447. }
  448. </style>