如何在vue js中唯一地创建组件?

时间:2020-02-17 03:42:23

标签: vue.js vue-component

我是Vue js的新手,通过视频教程学习,我创建了一个产品页面,每个产品都会有产品详细信息和审阅表单,因此,问题是,在为prodcut1提交审阅表单时,将为产品2存储相同的审阅和3并显示在他们的评论中 一旦看到此链接https://codepen.io/lakshmi123__/pen/mdJdrYG js代码:

// This is one vue component named as product
// Every component will have a template,data and methods
var eventBus = new Vue()
//Component1
Vue.component('product', {
  props:{
    premium:{
      type:Boolean,
      required:true
    }
  },
  template:
  `  <div class="product">
     <div class = "row"
      <div class="row ml-2">
       <div class="col">
       <div class="product-image mt-5 ml-4">
       <img v-bind:src="image">
       <div v-for="(variant,index) in variants"          :key="variant.variantId"
       class="color-box ml-3"
       :style="{ backgroundColor:          variant.variantColor }"
      @mouseover="updateProduct(index)">
      </div>
    <div class="product-info ml-3 mt-1">
    <h4><b>{{ title }}</b></h4>
    <!--Here we have written if-else-if using conditions == ,<,-->
    <p v-if="InStock">In Stock</p>
    <p v-else
    :class="{outOf:!InStock}">Out of Stock</p>
    <p>User is premium: {{ premium }}</p>
    <p>Shipping : {{shipping}}</p>
    <!--Here v-show is nothing but it just toggles the visibility of html element on the web page-->
    <p v-show="Shipping">Shipping cost includes</p>
    <span v-if="OnSale">{{ sale }}</span>
    <div class="Product-Details ml-4 mt-4">
    <h4><b>Details</b></h4>
    <ul>
    <li v-for="detail in details">{{ detail }}</li>
    </ul>
    </div>
    <div class="cart1 mt-3 mb-3">
    <button id="click" v-on:click="addToCart" 
    :disabled="!InStock"
    :class="{ disabledButton: !InStock }">Add to Cart</button>
    <button id="click" v-on:click="deleteFromCart"
    :disabled="!InStock"
    :class="{ disabledButton: !InStock }">Delete from Cart</button>
    </div>
    </div>
    <product-tabs1 :reviews="reviews"></product-tabs1>


     `,
// In this template at the last we are having another component called product-tabs it is actually the another component but
// is nested in the other component called product we will do like this because we want the product-tabs component to be displayed 
// in the product component like that we can implement nesting of components 


    data(){
        return {
            id:1,
            brand:'Vue Mastery',
            product: 'Socks',
            shipping:'Shipping:0',
            selectedVariant:0,
            Shipping:true,
            details:['80%cotton','20%polester','Gender-neutral'],
            selectedVariant : 0,
            variants:[
            {
                variantId: 2234,
                variantColor: "gray",
                variantImage:"gray.jpeg",
                variantQuantity: 10,
            },
            {
                variantId: 2235,
                variantColor: "blue",
                variantImage:"blue.jpeg",
                variantQuantity: 0
            }
            ],
            reviews:[],

            OnSale:false,
        }
    },
    methods:{
        addToCart(){
            this.$emit('add-to-cart')//this emit is used for letting the parent know that the button was clicked
            // since here the add-to-cart is the name of the event  associated with the add-to-cart button

        },
        updateProduct:function(variantImage){
            this.image=variantImage;
        },
        deleteFromCart:function(){
            this.$emit('delete-from-cart')
        },
        updateProduct(index){
            this.selectedVariant = index
            console.log(index)
        },
        addReview(productReview){
            this.reviews.push(productReview)

        }
    },
    computed:{
        title(){
            return this.brand + ' ' + this.product
        },
        image(){
            return this.variants[this.selectedVariant].variantImage
        },
        InStock(){
            return this.variants[this.selectedVariant].variantQuantity
        },
        sale(){
            if(this.OnSale){
                return this.brand + ' ' +this.product + ' is on sale!'
            }
            return this.brand + ' ' +this.product + ' is not on sale!'
        },
        shipping(){
            if(this.premium){
                return "Free"
            }
            return 2.99
           }
        },
        mounted() {
        eventBus.$on('review-submitted', productReview => {
          this.reviews.push(productReview)
        })
    }   
})

Vue.component('product-tabs1', {
    props: {
      reviews: {
        type: Array,
        required: false
      }
    },
    template: `
       <div>

        <div>
          <span class="tabs ml-3 mt-3" 
                :class="{ activeTab: selectedTab === tab }"
                v-for="(tab, index) in tabs"
                :key="index"
                @click="selectedTab = tab"
          >{{ tab }}</span>
        </div>

        <div v-show="selectedTab === 'Reviews'">
            <p class="para ml-4" v-if="!reviews.length">There are no reviews yet.</p>
            <ul v-else>
                <li v-for="review in reviews">
                  <p>{{ review.name }}</p>
                  <p>Rating:{{ review.rating }}</p>
                  <p>{{ review.review }}</p>
                </li>
            </ul>
        </div>

        <div v-show="selectedTab === 'Make a Review'">
          <product-review1></product-review1>
        </div>

      </div>
    `,
    data() {
      return {
        tabs: ['Reviews', 'Make a Review'],
        selectedTab: 'Reviews'
      }
    }
  })
Vue.component('product-review1',{
    template:

    `
    <form class ="review-form mt-3" @submit.prevent="onSubmit">
    <p v-if="errors.length">
      <b>Please correct the following error(s):</b>
      <ul>
      <li v-for="error in errors">{{ error }}</li>
      </ul>
      </p>
    <h5> Please give your review</h5>
    <p>
    <label for="name">Name:</label><br>
    <input id="name" v-model="name">
    </p>

    <p>
    <label for="review">Review:</label>
    <textarea id="review" v-model="review"></textarea>
    </p>

    <p>
    <label for="rating">Rating:</label>
    <select id="rating" v-model.number="rating">
    <option>5</option>
    <option>4</option>
    <option>3</option>
    <option>2</option>  
    <option>1</option>
    </select>
   </p>
   <p>Would you recommend this product?</p>
   <label>
   Yes
   <input type="radio" value="Yes" v-model="recommend"/>
   </label>
   <label>
   No
   <input type="radio" value="No" v-model="recommend"/>
   </label>
   <p>

   <p>
   <input type="submit" value="submit">
   </p>
   </form>

    `
    ,
    data(){
        return {
            name:null,
            review:null,
            rating:null,
            recommend:null,
            errors:[]
        }
    },
    methods: {
      onSubmit() {
        this.errors = []
        if (this.name && this.review && this.rating && this.recommend) {
          let productReview = {
            name: this.name,
            review: this.review,
            rating: this.rating,
            recommend: this.recommend
          }
          eventBus.$emit('review-submitted', productReview)
          this.name = null
          this.review = null
          this.rating = null
          this.recommend = null
        }
        else {
          if(!this.name) this.errors.push("Name required.")
          if(!this.review) this.errors.push("Review required.")
          if(!this.rating) this.errors.push("Rating required.")
          if(!this.recommend) this.errors.push("Recommend required")
        }
      }
    }
  })

//component2

Vue.component('product2', {
    props:{
        premium:{
            type:Boolean,
            required:true

        }

    },
    template:
    `<div class="product2">
     <div class = "row"
     <div class="row ml-2">
     <div class="col">
     <div class="product-image mt-5 ml-4">
     <img v-bind:src="image">

     <div v-for="(variant,index) in variants" :key="variant.variantId"
     class="color-box ml-3"
     :style="{ backgroundColor: variant.variantColor }"
     @mouseover="updateProduct(index)">
     </div>
     <div class="product-info ml-2 mt-1">
     <h4><b>{{ title }}</b></h4>
     <!--Here we have written if-else-if using conditions == ,<,-->
     <p v-if="InStock">In Stock</p>
     <p v-else
     :class="{outOf:!InStock}">Out of Stock</p>
     <p class="premium  mb-3">User is premium: true</p>
     <img src="free.jpeg" class="freeshi" width="10" height="10">
     <!--Here v-show is nothing but it just toggles the visibility of html element on the web page-->
     <p v-if="Shipping">Shipping cost includes</p>
     <p v-else
     :class="{Noshipping:!Shipping}">Shipping is Free</p>
     <span v-if="OnSale">{{ sale }}</span>
     <div class="Product-Details ml-4 mt-4">
     <h4><b>Details</b></h4>
     <ul>
     <li v-for="detail in details">{{ detail }}</li>
     </ul>
     </div>
     <div class="cart1 mt-3 mb-3">
     <button id="click" v-on:click="addToCart" 
     :disabled="!InStock"
     :class="{ disabledButton: !InStock }">Add to Cart</button>
     <button id="click" v-on:click="deleteFromCart"
     :disabled="!InStock"
     :class="{ disabledButton: !InStock }">Delete from Cart</button>

     </div>
     </div>

     <product-tabs2 :reviews="reviews"></product-tabs2>

     `,


    data(){
        return {
            id:1,
            brand:'Jockey',
            product: 'Socks',
            shipping:'Shipping:0',
            selectedVariant:0,
            Shipping:false,
            details:['Nocotton','Purepolyster','Gender-neutral'],
            selectedVariant : 0,
            variants:[
            {
                variantId: 2234,
                variantColor: "pink",
                variantImage:"pink2.jpg",
                variantQuantity: 10,
            },
            {
                variantId: 2235,
                variantColor: "green",
                variantImage:"green.jpeg",
                variantQuantity: 0
            }
            ],
            reviews:[],
            OnSale:false,
        }
    },
    methods:{
        addToCart(){
            this.$emit('add-to-cart')//this emit is used for letting the parent know that the button was clicked
            // since here the add-to-cart is the name of the event  associated with the add-to-cart button

        },
        updateProduct:function(variantImage){
            this.image=variantImage;
        },
        deleteFromCart:function(){
            this.$emit('delete-from-cart')
        },
        updateProduct(index){
            this.selectedVariant = index
            console.log(index)
        },
        addReview(productReview){
            this.reviews.push(productReview)

        }
    },
    computed:{
        title(){
            return this.brand + ' ' + this.product
        },
        image(){
            return this.variants[this.selectedVariant].variantImage
        },
        InStock(){
            return this.variants[this.selectedVariant].variantQuantity
        },
        sale(){
            if(this.OnSale){
                return this.brand + ' ' +this.product + ' is on sale!'
            }
            return this.brand + ' ' +this.product + ' is not on sale!'
        },
        shipping(){
            if(this.premium){
                return "Free"
            }
            return 2.99
        }
    },
    mounted() {
        eventBus.$on('review-submitted', productReview => {
          this.reviews.push(productReview)
        })
    }   
})

Vue.component('product3', {
    props:{
        premium:{
            type:Boolean,
            required:true

        }

    },
    template:
    `<div class="product3">
     <div class = "row"
     <div class="row ml-2">
     <div class="col">
     <div class="product-image mt-5 ml-4">
     <img v-bind:src="image">

     <div v-for="(variant,index) in variants" :key="variant.variantId"
     class="color-box ml-3"
     :style="{ backgroundColor: variant.variantColor }"
     @mouseover="updateProduct(index)">
     </div>
     <div class="product-info ml-3 mt-1">
     <h4><b>{{ title }}</b></h4>
     <!--Here we have written if-else-if using conditions == ,<,-->
     <p v-if="InStock">In Stock</p>
     <p v-else
     :class="{outOf:!InStock}">Out of Stock</p>
     <p>User is premium: {{ premium }}</p>
     <p>Shipping : {{shipping}}</p>
     <!--Here v-show is nothing but it just toggles the visibility of html element on the web page-->
     <p v-show="Shipping">Shipping cost includes</p>
     <span v-if="OnSale">{{ sale }}</span>
     <div class="Product-Details ml-4 mt-4">
     <h4><b>Details</b></h4>
     <ul>
     <li v-for="detail in details">{{ detail }}</li>
     </ul>
     </div>
     <div class="cart1 mt-3 mb-3">
     <button id="click" v-on:click="addToCart" 
     :disabled="!InStock"
     :class="{ disabledButton: !InStock }">Add to Cart</button>
     <button id="click" v-on:click="deleteFromCart"
     :disabled="!InStock"
     :class="{ disabledButton: !InStock }">Delete from Cart</button>

     </div>
     </div>
     <product-tabs3 :reviews="reviews"></product-tabs3>

     `,


    data(){
        return {
            id:1,
            brand:'Paragon',
            product: 'Socks',
            shipping:'Shipping:0',
            selectedVariant:0,
            Shipping:true,
            details:['PureCotton','NoPolyster','Gender-neutral'],
            selectedVariant : 0,
            variants:[
            {
                variantId: 2234,
                variantColor: "red",
                variantImage:"red1.jpeg",
                variantQuantity: 10,
            },
            {
                variantId: 2235,
                variantColor: "black",
                variantImage:"black1.jpeg",
                variantQuantity: 0
            }
            ],
            reviews:[],

            OnSale:false,
        }
    },
    methods:{
        addToCart(){
            this.$emit('add-to-cart')//this emit is used for letting the parent know that the button was clicked
            // since here the add-to-cart is the name of the event  associated with the add-to-cart button

        },
        updateProduct:function(variantImage){
            this.image=variantImage;
        },
        deleteFromCart:function(){
            this.$emit('delete-from-cart')
        },
        updateProduct(index){
            this.selectedVariant = index
            console.log(index)
        },
        addReview(productReview){
            this.reviews.push(productReview)

        }
    },
    computed:{
        title(){
            return this.brand + ' ' + this.product
        },
        image(){
            return this.variants[this.selectedVariant].variantImage
        },
        InStock(){
            return this.variants[this.selectedVariant].variantQuantity
        },
        sale(){
            if(this.OnSale){
                return this.brand + ' ' +this.product + ' is on sale!'
            }
            return this.brand + ' ' +this.product + ' is not on sale!'
        },
        shipping(){
            if(this.premium){
                return "Free"
            }
            return 2.99
        }
    },
    mounted() {
        eventBus.$on('review-submitted', productReview => {
          this.reviews.push(productReview)
        })
    }   
})


Vue.component('product-review1',{
    template:

    `
    <form class ="review-form mt-3" @submit.prevent="onSubmit">
    <p v-if="errors.length">
      <b>Please correct the following error(s):</b>
      <ul>
      <li v-for="error in errors">{{ error }}</li>
      </ul>
      </p>
    <h5> Please give your review</h5>
    <p>
    <label for="name">Name:</label><br>
    <input id="name" v-model="name">
    </p>

    <p>
    <label for="review">Review:</label>
    <textarea id="review" v-model="review"></textarea>
    </p>

    <p>
    <label for="rating">Rating:</label>
    <select id="rating" v-model.number="rating">
    <option>5</option>
    <option>4</option>
    <option>3</option>
    <option>2</option>  
    <option>1</option>
    </select>
   </p>
   <p>Would you recommend this product?</p>
   <label>
   Yes
   <input type="radio" value="Yes" v-model="recommend"/>
   </label>
   <label>
   No
   <input type="radio" value="No" v-model="recommend"/>
   </label>
   <p>

   <p>
   <input type="submit" value="submit">
   </p>
   </form>

    `
    ,
    data(){
        return {
            name:null,
            review:null,
            rating:null,
            recommend:null,
            errors:[]
        }
    },
    methods: {
      onSubmit() {
        this.errors = []
        if (this.name && this.review && this.rating && this.recommend) {
          let productReview = {
            name: this.name,
            review: this.review,
            rating: this.rating,
            recommend: this.recommend
          }
          eventBus.$emit('review-submitted', productReview)
          this.name = null
          this.review = null
          this.rating = null
          this.recommend = null
        }
        else {
          if(!this.name) this.errors.push("Name required.")
          if(!this.review) this.errors.push("Review required.")
          if(!this.rating) this.errors.push("Rating required.")
          if(!this.recommend) this.errors.push("Recommend required")
        }
      }
    }
  })

//this is for tabs component to get the tabs at the end for reviews in one and make a review in another tab


//this is for tabs component to get the tabs at the end for reviews in one and make a review in another tab
Vue.component('product-tabs2', {
    props: {
      reviews: {
        type: Array,
        required: false
      }
    },
    template: `
       <div>

        <div>
          <span class="tabs ml-3 mt-3" 
                :class="{ activeTab: selectedTab === tab }"
                v-for="(tab, index) in tabs"
                :key="index"
                @click="selectedTab = tab"
          >{{ tab }}</span>
        </div>

        <div v-show="selectedTab === 'Reviews'">
            <p class="para ml-4" v-if="!reviews.length">There are no reviews yet.</p>
            <ul v-else>
                <li v-for="review in reviews">
                  <p>{{ review.name }}</p>
                  <p>Rating:{{ review.rating }}</p>
                  <p>{{ review.review }}</p>
                </li>
            </ul>
        </div>

        <div v-show="selectedTab === 'Make a Review'">
          <product-review2></product-review2>
        </div>

      </div>
    `,
    data() {
      return {
        tabs: ['Reviews', 'Make a Review'],
        selectedTab: 'Reviews'
      }
    }
  })
Vue.component('product-review2',{
    template:

    `
    <form class ="review-form mt-3" @submit.prevent="onSubmit">
    <p v-if="errors.length">
      <b>Please correct the following error(s):</b>
      <ul>
      <li v-for="error in errors">{{ error }}</li>
      </ul>
      </p>
    <h5> Please give your review</h5>
    <p>
    <label for="name">Name:</label><br>
    <input id="name" v-model="name">
    </p>

    <p>
    <label for="review">Review:</label>
    <textarea id="review" v-model="review"></textarea>
    </p>

    <p>
    <label for="rating">Rating:</label>
    <select id="rating" v-model.number="rating">
    <option>5</option>
    <option>4</option>
    <option>3</option>
    <option>2</option>  
    <option>1</option>
    </select>
   </p>
   <p>Would you recommend this product?</p>
   <label>
   Yes
   <input type="radio" value="Yes" v-model="recommend"/>
   </label>
   <label>
   No
   <input type="radio" value="No" v-model="recommend"/>
   </label>
   <p>

   <p>
   <input type="submit" value="submit">
   </p>
   </form>

    `
    ,
    data(){
        return {
            name:null,
            review:null,
            rating:null,
            recommend:null,
            errors:[]
        }
    },
    methods: {
      onSubmit() {
        this.errors = []
        if (this.name && this.review && this.rating && this.recommend) {
          let productReview = {
            name: this.name,
            review: this.review,
            rating: this.rating,
            recommend: this.recommend
          }
          eventBus.$emit('review-submitted', productReview)
          this.name = null
          this.review = null
          this.rating = null
          this.recommend = null
        }
        else {
          if(!this.name) this.errors.push("Name required.")
          if(!this.review) this.errors.push("Review required.")
          if(!this.rating) this.errors.push("Rating required.")
          if(!this.recommend) this.errors.push("Recommend required")
        }
      }
    }
  })
Vue.component('product-tabs3', {
    props: {
      reviews: {
        type: Array,
        required: false
      }
    },
    template: `
       <div>

        <div>
          <span class="tabs ml-3 mt-3" 
                :class="{ activeTab: selectedTab === tab }"
                v-for="(tab, index) in tabs"
                :key="index"
                @click="selectedTab = tab"
          >{{ tab }}</span>
        </div>

        <div v-show="selectedTab === 'Reviews'">
            <p class="para ml-4" v-if="!reviews.length">There are no reviews yet.</p>
            <ul v-else>
                <li v-for="review in reviews">
                  <p>{{ review.name }}</p>
                  <p>Rating:{{ review.rating }}</p>
                  <p>{{ review.review }}</p>
                </li>
            </ul>
        </div>

        <div v-show="selectedTab === 'Make a Review'">
          <product-review2></product-review2>
        </div>

      </div>
    `,
    data() {
      return {
        tabs: ['Reviews', 'Make a Review'],
        selectedTab: 'Reviews'
      }
    }
  })
Vue.component('product-review3',{
    template:

    `
    <form class ="review-form mt-3" @submit.prevent="onSubmit">
    <p v-if="errors.length">
      <b>Please correct the following error(s):</b>
      <ul>
      <li v-for="error in errors">{{ error }}</li>
      </ul>
      </p>
    <h5> Please give your review</h5>
    <p>
    <label for="name">Name:</label><br>
    <input id="name" v-model="name">
    </p>

    <p>
    <label for="review">Review:</label>
    <textarea id="review" v-model="review"></textarea>
    </p>

    <p>
    <label for="rating">Rating:</label>
    <select id="rating" v-model.number="rating">
    <option>5</option>
    <option>4</option>
    <option>3</option>
    <option>2</option>  
    <option>1</option>
    </select>
   </p>
   <p>Would you recommend this product?</p>
   <label>
   Yes
   <input type="radio" value="Yes" v-model="recommend"/>
   </label>
   <label>
   No
   <input type="radio" value="No" v-model="recommend"/>
   </label>
   <p>

   <p>
   <input type="submit" value="submit">
   </p>
   </form>

    `
    ,
    data(){
        return {
            name:null,
            review:null,
            rating:null,
            recommend:null,
            errors:[]
        }
    },
    methods: {
      onSubmit() {
        this.errors = []
        if (this.name && this.review && this.rating && this.recommend) {
          let productReview = {
            name: this.name,
            review: this.review,
            rating: this.rating,
            recommend: this.recommend
          }
          eventBus.$emit('review-submitted', productReview)
          this.name = null
          this.review = null
          this.rating = null
          this.recommend = null
        }
        else {
          if(!this.name) this.errors.push("Name required.")
          if(!this.review) this.errors.push("Review required.")
          if(!this.rating) this.errors.push("Rating required.")
          if(!this.recommend) this.errors.push("Recommend required")
        }
      }
    }
  })

var app = new Vue({
    el:'#app',
    data:{
        premium:false,
        cart:[]
    },
    methods:{
        updateCart(id){
            this.cart.push(id)
        },
        degradeCart(id){
            this.cart.pop(id);
        }
    }


})








/*In this vue methods section we are two types of methods one is normal functions and the other is the computed properties
 In the normal functions I took the addToCart and deleteToCart functions for incrementing and decrementing the items from the cart
 In the computed properties 
 1.there is title(), image(), InStock() methods title() methods is for printing the product name with 
 the brand that means in the title return statement I had returned the brand and product names together.
 2. there is image() method will display image based on selected Variant in default the selected variant is 0 that is gray here and
 if it is 1 then blue color.
 3. there is InStock() method will display the Instock ad outOfStock messages in the front end based on the quantity taken here
 for gray color socks I had took quantity:10 so instock and for blue color I had took quantity:0 so OutofStock will be displayed
 Here we used props A prop is a custom attribute for passing data into our components
 In order to receive props a component should explicitly call the props 
 So for example
  Vue.component('product',{
   props:[message],
   template:`<div>{{message}}</div>,
   data(){...}
  })
  In the props we have called the message and in the html template we had rendered`


  */

1 个答案:

答案 0 :(得分:0)

您只有一个eventBus,但是您所有的组件都在监听提交的事件。因此,每当有任何评论发表时,所有组件都将其添加。

通常,您在这里只有一个组件,可以多次使用,将不同的产品作为道具传递,而不是复制整个组件。这可能是解决此问题的最佳方法。 (此示例似乎来自VueMastery系列,尽管如此,他们还是可以带您进入的。)

但是您也可以通过在评论中添加产品标识符并让每个侦听器检查其是否适用于此问题来解决此问题。 (请记住,这是一个玩具项目。在任何实际项目中,都会有一些中央商店,例如Vuex,负责管理所有产品的所有评论。)