Vue.js 不会遵守多个实例

Vue.js won't adhere to multiple instances

我尝试使用 Vue.js 创建一个评论按钮。但是,“赞”按钮似乎只对一条评论(第一条)起作用,而第二条评论似乎甚至无法识别 Vue.js 语法。有人能指出我正确的方向吗?

代码笔:http://codepen.io/chrisburton/pen/EVKLxL


new Vue({
  el: '.containComments',

  data: {
      liked: false,

      likesCount: 0
  },

  methods: {
      toggleLike: function() {
          this.liked = ! this.liked;

          this.liked ? this.likesCount++ : this.likesCount--;
      }
  }

});
@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,200italic,300italic);

@import url(https://dl.dropboxusercontent.com/u/26380646/rocknroll/assets/style.css);

* {-webkit-box-sizing: border-box;-moz-box-sizing: border-box;-o-box-sizing: border-box;box-sizing: border-box;}
a {
  -webkit-transition: .1s color linear;
  -moz-transition: .1s color linear;
  -o-transition: .1s color linear;
  transition: .1s color linear;
}
a:hover {
  -webkit-transition: .25s color linear;
  -moz-transition: .25s color linear;
  -o-transition: .25s color linear;
  transition: .25s color linear;
}


/*
************************
Project Start
************************
*/

html {font-size: 18px;}

body {
  background:;
  color: #404040;
  font-family: 'Source Sans Pro', Georgia;
  font-size: 1em;
  font-weight: 200;
  line-height: 1.65;
  letter-spacing: .01em;
  margin: 50px 0;
  padding: 0 25px;
}

section {
  max-width: 500px;
  min-width: 300px;
  margin: 50px auto;
}

div.containComments { 
  position: relative;
  border-bottom: solid 1px rgba(178, 179, 153, .15);
  margin: 0 auto 50px auto;
}
div.containComments:last-child {
  border: none;
}

p.username {
  font-weight: 300;
  margin-bottom: 25px; 
}

p.username a {
  color: #BFBFA8;
  text-transform: lowercase; 
  text-decoration: none;
}
.reply {
  color: #BFBFA8;
  cursor: pointer;
}

p.username a:hover {color: #000;}

p.username img.maskable {
  position: absolute;
  top: -10px;
  left: -70px;
  width: 50px;
  height: 50px;
  border-width: 0; 
  border-radius: 100%;
}

.likesCount, 
.icon-rocknroll {
  position: relative;
  float: right;
  opacity: 0;
}
.likesCount {
  top: 4px;
  left: 0;
  font-size: 15px;
  margin-right: .05em;
}
.icon-rocknroll {
  top: 7px;
  left: 0;
  background: none;
  border: 0;
  outline: none;
  font-family: "icons";
  font-size: 13px;
  opacity: 0;
  cursor: pointer;
}

div.containComments:hover .icon-rocknroll {
  opacity: .44;
}
div.containComments:hover .icon-rocknroll:hover,
div.containComments:hover .likesCount {
  opacity: .75;
}

.active, 
active:hover,
div.containComments:hover .active {
  opacity: .75;
}
div.containComments:hover .active:hover {
  opacity: .44;
}

p.info {
  font-size: 18px;
  margin-bottom: 50px;
}

code {
  font-family: "Source Code Pro";
}


/* Break */
@media (max-width: 775px) {
  section {max-width: 400px;}
  .icon-rocknroll {float: right;}
}

/* Smartphones Landscape */
@media (max-width: 600px) {
  section {max-width: 350px;}
  div.containComments {padding: 0 25px;}
  img.maskable {
    position: relative !important;
    top:0 !important;
    left: 0 !important;
    display: inline-block;
    vertical-align: middle;
    margin-right: 5px;
  }
  .icon-rocknroll {
    float: right;
    top: 16px;
  }
  .likesCount {
    top: 12px;
  }
  p.info {margin-left: 0;}
  .closed {
    width: 280px;
  }
}







/* Smartphones Portrait */
@media (max-width: 500px) {
  body {padding: 0;}
  section {max-width: 270px;}
  img.maskable {
    position: relative !important;
    top:0 !important;
    left: 0 !important;
    display: inline-block;
    vertical-align: middle;
    margin-right: 5px;
  }
  .icon-rocknroll {
    float: right;
    top: 15px;
  }
  p.info {margin-left: 0;}
  .closed {
    width: 270px;
    text-align: center;
    margin: 0 auto 50px auto;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.14/vue.min.js"></script>
<section class="comments">
  
  
  <div class="containComments">
    <p class="username">
      <img class="maskable" src="https://en.gravatar.com/userimage/18343163/cf3a7b15b60479a37b2167e84ffb85a6.jpg?size=100" /> 
      <a href="https://twitter.com/chrisburton">chrisburton</a>
      <button class="icon-rocknroll" v-class="active: liked" v-on="click: toggleLike"></button>
      <span class="likesCount" v-class="active: liked">{{ likesCount }}</span>
    </p>
    <p class="info">Thank you for visiting all the way from New York. This is just a test to determine if the Twitter API is working as it should. You should see your profile image and your username at the very top that links to your account. You should also see that I wrote in a thank you introduction with your location.</p>
  </div>

  <div class="containComments">
    <p class="username first">
      <img class="maskable" src="http://assets.arabiaweddings.com/sites/default/files/news/2014/06/anna.jpg" /> 
      <a href="#">AnnaWintour</a>
      <button class="icon-rocknroll" v-class="active: liked" v-on="click: toggleLike"></button>
      <span class="likesCount" v-class="active: liked">{{ likesCount }}</span>
    </p>
    <p class="info first"><span class="reply">@chrisburton</span> +1. Really interesting reply.</p>
  </div>

  
</section>

您必须使用模板创建 Vue.component 才能重复使用代码。

Vue.js

Vue.component('like', {
    template: "<button class='icon-rocknroll' v-class='active: liked' v-on='click: toggleLike'></button>\
               <span class='likesCount' v-class='active: liked'>{{ likesCount }}</span>",
    data: function() {
        return {
            liked: false,
            likesCount: 0
        }
    },
    methods: {
        toggleLike: function() {
            this.liked = !this.liked;
            this.liked ? this.likesCount++ : this.likesCount--;
        }
    }
});
new Vue({
    el: '#app',
});

HTML

<like></like>