main.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. let eventBus = new Vue(
  2. );
  3. Vue.component('product', {
  4. props: {
  5. premium: {
  6. type: Boolean,
  7. required: true
  8. }
  9. },
  10. template: `
  11. <div class="product">
  12. <div class="product-image">
  13. <img :src="image" :alt="altText"/>
  14. </div>
  15. <div class="product-info">
  16. <h1>{{ title }}</h1>
  17. <p v-if="inStock">In stock</p>
  18. <p v-else>Out of Stock</p>
  19. <p>Shipping: {{ shipping }}</p>
  20. <product-details></product-details>
  21. <div
  22. class="color-box"
  23. v-for="(variant, index) in variants"
  24. :key="variant.variantId"
  25. :style="{ backgroundColor:variant.variantColor }"
  26. @mouseover="updateProduct(index)"
  27. ></div>
  28. </div>
  29. <button
  30. @click="addToCart"
  31. :disabled="!inStock"
  32. :class="{ disabledButton: !inStock }"
  33. >
  34. Add to cart
  35. </button>
  36. <button
  37. @click="removeToCart"
  38. :disabled="!inStock"
  39. :class="{ disabledButton: !inStock }"
  40. >
  41. remove to cart
  42. </button>
  43. <product-tabs :reviews="reviews"></product-tabs>
  44. </div>
  45. `,
  46. data() {
  47. return {
  48. product: "Socks",
  49. reviews: [],
  50. brand: 'Vue Mastery',
  51. selectedVariant: 0,
  52. altText: "A pair of socks",
  53. details: ['80% cotton', '20% polyester', 'Gender-neutral'],
  54. variants: [
  55. {
  56. variantId: 2234,
  57. variantColor: 'green',
  58. variantImage: "./assets/vmSocks-green-onWhite.jpg",
  59. variantQuantity: 10
  60. },
  61. {
  62. variantId: 2235,
  63. variantColor: 'blue',
  64. variantImage: "./assets/vmSocks-blue-onWhite.jpg",
  65. variantQuantity: 0
  66. }
  67. ],
  68. cart: 0
  69. }
  70. },
  71. mounted() {
  72. eventBus.$on('review-submitted', productReview => {
  73. this.reviews.push(productReview)
  74. })
  75. },
  76. methods: {
  77. addToCart() {
  78. this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);
  79. },
  80. removeToCart() {
  81. this.$emit('remove-to-cart', this.variants[this.selectedVariant].variantId);
  82. },
  83. updateProduct(index) {
  84. this.selectedVariant = index;
  85. console.log(index);
  86. },
  87. },
  88. computed: {
  89. title() {
  90. return this.brand + ' ' + this.product;
  91. },
  92. image() {
  93. return this.variants[this.selectedVariant].variantImage;
  94. },
  95. inStock() {
  96. return this.variants[this.selectedVariant].variantQuantity
  97. },
  98. shipping() {
  99. if (this.premium) {
  100. return "Free";
  101. } else {
  102. return 2.99
  103. }
  104. }
  105. }
  106. })
  107. Vue.component('product-details', {
  108. data() {
  109. return {
  110. details: ['80% cotton', '20% polyester', 'Gender-neutral'],
  111. }
  112. },
  113. template: `
  114. <ul>
  115. <li v-for="detail in details">{{ detail }}</li>
  116. </ul>
  117. `
  118. ,
  119. });
  120. Vue.component('product-review', {
  121. template: `
  122. <form class="review-form" @submit.prevent="onSubmit">
  123. <p v-if="errors.length">
  124. <b>Please correct the following error(s):</b>
  125. <ul>
  126. <li v-for="error in errors">{{ error }}</li>
  127. </ul>
  128. </p>
  129. <p>
  130. <label for="name">Name:</label>
  131. <input id="name" v-model="name" placeholder="name">
  132. </p>
  133. <p>
  134. <label for="name">Would you recommend this product?:</label>
  135. <input id="name" v-model="radio" type="radio" value="yes" placeholder="no">
  136. <input id="name" v-model="radio" type="radio" value="no" placeholder="yes">
  137. </p>
  138. <p>
  139. <label for="review">Review:</label>
  140. <textarea id="review" v-model="review"></textarea>
  141. </p>
  142. <p>
  143. <label for="rating">Rating:</label>
  144. <select id="rating" v-model.number="rating">
  145. <option>5</option>
  146. <option>4</option>
  147. <option>3</option>
  148. <option>2</option>
  149. <option>1</option>
  150. </select>
  151. </p>
  152. <p>
  153. <input type="submit" value="Submit">
  154. </p>
  155. </form>
  156. `,
  157. data() {
  158. return {
  159. name: null,
  160. review: null,
  161. rating: null,
  162. radio: null,
  163. errors: []
  164. }
  165. },
  166. methods: {
  167. onSubmit() {
  168. if(this.name && this.review && this.rating&& this.radio) {
  169. let productReview = {
  170. name: this.name,
  171. review: this.review,
  172. rating: this.rating,
  173. radio: this.radio,
  174. }
  175. eventBus.$emit('review-submitted', productReview)
  176. this.name = null
  177. this.review = null
  178. this.rating = null
  179. this.radio = null
  180. } else {
  181. if(!this.name) this.errors.push("Name required.")
  182. if(!this.review) this.errors.push("Review required.")
  183. if(!this.rating) this.errors.push("Rating required.")
  184. if(!this.radio) this.errors.push("Radio required.")
  185. }
  186. }
  187. }
  188. })
  189. Vue.component('product-tabs', {
  190. props: {
  191. reviews: {
  192. type: Array,
  193. required: false
  194. }
  195. },
  196. template: `
  197. <div>
  198. <ul>
  199. <span class="tab"
  200. :class="{ activeTab: selectedTab === tab }"
  201. v-for="(tab, index) in tabs"
  202. @click="selectedTab = tab"
  203. >{{ tab }}</span>
  204. </ul>
  205. <div v-show="selectedTab === 'Reviews'">
  206. <p v-if="!reviews.length">There are no reviews yet.</p>
  207. <ul>
  208. <li v-for="review in reviews">
  209. <p>{{ review.name }}</p>
  210. <p>Rating: {{ review.rating }}</p>
  211. <p>{{ review.review }}</p>
  212. </li>
  213. </ul>
  214. </div>
  215. <div v-show="selectedTab === 'Make a Review'">
  216. <product-review></product-review>
  217. </div>
  218. </div>
  219. `,
  220. data() {
  221. return {
  222. tabs: ['Reviews', 'Make a Review'],
  223. selectedTab: 'Reviews' // устанавливается с помощью @click
  224. }
  225. },
  226. })
  227. let app = new Vue({
  228. el: '#app',
  229. data: {
  230. premium: true,
  231. cart: []
  232. },
  233. methods: {
  234. updateCart(id) {
  235. this.cart.push(id);
  236. },
  237. removeCart(id) {
  238. let i = this.cart.indexOf(id);
  239. this.cart.splice(i, 1);
  240. }
  241. }
  242. })