<html>
  <head>
  </head>
  <body>
    <div id="ticker">
    <h1>Ticker with vue.js</h1>
    <sbticker>
    </sbticker>
    </div>
   <body>
</html>

<script type="text/x-template" id="tickerTpl">
  <div>
  <div class="progress" v-if="News.length > 1"></div>
  <ul class="horizontalList ticker-list">
    <li class="active-item" v-if="ActiveNewsItem != null"><a :href="ActiveNewsItem.Url" target="_blank">{{ ActiveNewsItem.Title }}</a></li>
  </ul>
  <ul class="horizontalList ticker-pagination-list" v-if="News.length > 1">

    <li class="ticker-page" v-for="(item, index) in News" @click="onTickerStatusIconClick(item)" v-bind:class="{ 'ticker-page-active': ActiveNewsItem != null && ActiveNewsItem.Id == item.Id }"></li>

  </ul>

  </div>

</script>
.horizontalList {
  list-style: none outside none;
  margin-bottom: 20px;
  margin-left: 0;
  margin-top: 0;
  padding:0;
}

.horizontalList:after, 
.horizontalList:before {
    content: "";
    display: table;
    line-height: 0;
}

.horizontalList:after {
    clear: both;
}

.horizontalList li {
    line-height: 20px;
    float: left;
}

.ticker-list {
  float:left;
  width:90%;
}

.ticker-pagination-list {
  float:right;
}

.ticker-list li {
  padding: 10px;
}

.ticker-list a {
  color: #000;
  text-decoration: none;
}

.ticker-page {
  border-radius: 50%;
	width: 10px;
	height: 10px;
  border: solid 2px #0099ff;
  margin: 2px;
  cursor:pointer;
}

.ticker-page-active {
  background: #0099ff;
}

.progress {
      height: 4px;
  animation: progressbar-countdown;
  /* Placeholder, this will be updated using javascript */
  animation-duration: 40s;
  /* We stop in the end */
  animation-iteration-count: 1;
  /* Stay on pause when the animation is finished finished */
  animation-fill-mode: forwards;
  /* We start paused, we start the animation using javascript */
  /* We want a linear animation, ease-out is standard */
  animation-timing-function: linear;
      animation-play-state: running;
    }
    
    @keyframes progressbar-countdown {
  0% {
    width: 0%;
    background: rgba(0, 153, 255, 1);
  }
  100% {
    width: 100%;
    background: rgba(0, 153, 255, 1);
  }
}
	Vue.component('sbticker', {
        template: "#tickerTpl",
        data: function () {
            return {
                ActiveNewsItem: null,
                News: [{
                  Title: "CSS: Nummerierte Liste mit unterpunkten",
                  Id: 1,
                  Url: "https://www.sb-websolutions.de/index.php?action=ViewBlogPost&postID=34&title=css-nummerierte-liste-mit-unterpunkten"
                },
                {
                  Title: "Preview: Neues ACP Design",
                  Id: 2,
                  Url: "https://www.sb-websolutions.de/index.php?action=ViewBlogPost&postID=33&title=preview-neues-acp-design"
                },
                      {
                        Title: "SBW goes social",
                        Id: 3,
                        Url: "https://www.sb-websolutions.de/index.php?action=ViewBlogPost&postID=32&title=sbw-goes-social"
                      }]
            };
        },
        mounted: function () {
            this.ActiveNewsItem = this.News[0];
            $(".progress").bind("animationend", this.onTickerEnd);
        },
        methods: {
            onTickerEnd: function () {
                var newsItem = this.NextNews;
                this.ActiveNewsItem = newsItem;
                this.resetProgressbar();
            },
            resetProgressbar: function() {
                //Clone ticker and remove it, to restart 
                var el = $(".progress");
                var clonedTicker = $(el).clone(true);
                $(el).before(clonedTicker);
                $(el).remove();
            },
            onTickerStatusIconClick: function (newsItem) {
                this.ActiveNewsItem = newsItem;
                this.resetProgressbar();
            }
        },
        computed: {
            NextNews: function () {
                var nextIndex = this.CurrentActiveNewsIndex + 1;
                var total = this.News.length;

                if (nextIndex >= total) {
                    nextIndex = 0;
                }

                return this.News[nextIndex];
            },
            CurrentActiveNewsIndex: function () {
                //NOT SUPPORTED IN IE9: return this.News.findIndex(x => x.ItemId == this.ActiveNewsItem.ItemId);

                for (var i = 0; i < this.News.length; i += 1) {
                    if (this.News[i]["Id"] === this.ActiveNewsItem.Id) {
                        return i;
                    }
                }

            }
        }
	});
          
          new Vue({
						        el: "#ticker"
						    });

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js