uni-notice-bar.vue 10 KB

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