欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

VUE 添加事件、渲染、组件

程序员文章站 2022-04-17 18:46:39
...

<!-- 1. 实例演示为元素添加事件的正确方式 2. 实例演示条件渲染与列表渲染,特别是数组对象 3. 实例演示计算属性与侦听器, 并分析二者区别 4. 实例演示组件与组件之间的通信,特别是如何监听子组件的数据变化 -->

VUE 元素添加事件

  • v-on: 事件指令 , 简写: @
  • event, 在 vue3: $evnet
  • 事件修饰符: 对当前的事件行为进行干预
  • @click.prevent: 阻止默认行为
  • @click.prevent.stop
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>事件绑定</title>
  8. <script src="https://unpkg.com/vue@next"></script>
  9. </head>
  10. <body>
  11. <!-- vue3 -->
  12. <div class="app">
  13. <p>
  14. <!-- v-on: 事件指令 , @ -->
  15. <!-- event, 在vue3: $evnet -->
  16. <a href="helo10086.cn" v-on:click="showUrl($event)">vue1: 显示网址: </a>
  17. <span class="url">{{url}}</span>
  18. </p>
  19. <!-- 事件修饰符: 对当前的事件行为进行干预 -->
  20. <p>
  21. <!-- v-on: 事件指令 , @ -->
  22. <!-- event, 在vue3: $evnet -->
  23. <!-- @click.prevent: 阻止默认行为 -->
  24. <a href="helo10086.cn" @click.prevent="this.url = $event.target.href"
  25. >vue2: 显示网址:
  26. </a>
  27. <span class="url">{{url}}</span>
  28. </p>
  29. <!-- 在父级上的同名事件,因为事件冒泡机制而被自动的调用了 -->
  30. <p onclick="alert('hello help!')">
  31. <!-- @click.stop: 阻止冒泡 -->
  32. <a
  33. href="helo10086.cn"
  34. @click.prevent.stop="this.url = $event.target.href"
  35. >vue3: 显示网址:
  36. </a>
  37. <span class="url">{{url}}</span>
  38. </p>
  39. </div>
  40. <script>
  41. const app = Vue.createApp({
  42. data() {
  43. return {
  44. url: null,
  45. };
  46. },
  47. methods: {
  48. showUrl(ev) {
  49. // 防止默认行为
  50. ev.preventDefault();
  51. console.log(ev === event);
  52. // this -> vue实例
  53. console.log(this);
  54. console.log(ev.target);
  55. this.url = ev.target.href;
  56. },
  57. },
  58. }).mount(".app");
  59. </script>
  60. </body>
  61. </html>

[http://help10086.cn/0114/demo1.html]

VUE 条件渲染与列表渲染

  • v-for , 对应原生的 for - of
  1. <!-- 列表渲染 -->
  2. <!DOCTYPE html>
  3. <html lang="zh-CN">
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  8. <title>列表渲染</title>
  9. <script src="https://unpkg.com/vue@next"></script>
  10. </head>
  11. <body>
  12. <div class="app">
  13. <!-- array: v-for , 对应原生的 for - of -->
  14. <ul>
  15. <!-- 提高效率,一定要加 :key 为了借助diff算法,key必须选择一个永远唯一的值 -->
  16. <li v-for="(city,index) of cities" :key="index">{{index}}->{{city}}</li>
  17. </ul>
  18. <!-- obj: v-for -->
  19. <ul>
  20. <!-- prop -> property 属性 -->
  21. <li v-for="(item,prop,index) of user" :key="index">
  22. {{index}} ->{{prop}} => {{item}}
  23. </li>
  24. </ul>
  25. <!-- ArrayObj: v-for -->
  26. <ul>
  27. <li v-for="(user,index) of users" :key="index">
  28. {{user.name}}: ({{user.email}})
  29. </li>
  30. </ul>
  31. </div>
  32. <script>
  33. const app = Vue.createApp({
  34. data() {
  35. return {
  36. // array
  37. cities: ["tayninh", "nhontrach", "longthanh"],
  38. // object
  39. user: {
  40. name: "help",
  41. email: "help@foxmail.com",
  42. },
  43. // array of object
  44. users: [
  45. {
  46. name: "lan",
  47. email: "lan@foxmail.com",
  48. },
  49. {
  50. name: "hoang",
  51. email: "hoang@foxmail.com",
  52. },
  53. {
  54. name: "hope",
  55. email: "hope@foxmail.com",
  56. },
  57. ],
  58. };
  59. },
  60. }).mount(".app");
  61. </script>
  62. </body>
  63. </html>
  64. <!-- 条件渲染 -->
  65. <!DOCTYPE html>
  66. <html lang="zh-CN">
  67. <head>
  68. <meta charset="UTF-8" />
  69. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  70. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  71. <title>条件渲染</title>
  72. <script src="https://unpkg.com/vue@next"></script>
  73. </head>
  74. <body>
  75. <div class="app">
  76. <!-- if -->
  77. <p v-if="flag">{{message}}</p>
  78. <button @click="flag=!flag" v-text="flag ? '隐藏' : '显示'"></button>
  79. <!-- if -- if else -- if else -- else -->
  80. <p v-if="salary > 0 && salary < 2000">{{grade[1]}}</p>
  81. <p v-else-if="salary >= 2000 && salary < 6000">{{grade[2]}}</p>
  82. <p v-else-if="salary >= 6000 && salary < 10000">{{grade[3]}}</p>
  83. <p v-else-if="salary >= 10000 && salary < 15000">{{grade[4]}}</p>
  84. <p v-else-if="salary >= 15000">{{grade[5]}}</p>
  85. <p v-else>{{grade[0]}}</p>
  86. </div>
  87. <script>
  88. const app = Vue.createApp({
  89. data() {
  90. return {
  91. message: "20220116, 准备领完年终奖,回家过年吧!",
  92. flag: false,
  93. // 会员级别
  94. grade: [
  95. "操作工",
  96. "业务员",
  97. "主管",
  98. "一般管理",
  99. "中层管理",
  100. "高层管理",
  101. ],
  102. // 积分
  103. salary: 100000,
  104. };
  105. },
  106. }).mount(".app");
  107. </script>
  108. </body>
  109. </html>

列表渲染:[http://help10086.cn/0114/demo2.html]
条件渲染:[http://help10086.cn/0114/demo3.html]

VUE 计算属性与侦听器

  • 例生命周期, mounted: 当 vue 实例加载完成的时候会自动调用(onload)
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <script src="https://unpkg.com/vue@next"></script>
  8. <title>计算属性,侦听器属性</title>
  9. <style>
  10. table {
  11. width: 26em;
  12. text-align: center;
  13. border-collapse: collapse;
  14. }
  15. table caption {
  16. font-size: 1.5em;
  17. margin-bottom: 0.6em;
  18. }
  19. thead {
  20. background-color: lightcyan;
  21. }
  22. th,
  23. td {
  24. border: 1px solid #000;
  25. height: 2em;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="app">
  31. <table>
  32. <caption>
  33. 购物车
  34. </caption>
  35. <thead>
  36. <tr>
  37. <th>ID</th>
  38. <th>品名</th>
  39. <th>单价</th>
  40. <th>数量</th>
  41. <th>金额</th>
  42. </tr>
  43. </thead>
  44. <tbody>
  45. <tr>
  46. <td>20220116</td>
  47. <td>iphone 13</td>
  48. <td>{{price}}</td>
  49. <td><input type="number" v-model="num" style="width: 4em" /></td>
  50. <!-- <td>{{price * num}}</td> -->
  51. <td>{{payAmount}}</td>
  52. </tr>
  53. </tbody>
  54. </table>
  55. <!-- 侦听器来监听金额的变化,设置优惠价格:用户实际支付的钱 -->
  56. <!-- <p>实付金额: {{disAmount}}, 优惠了 : <span style="color: red">{{payAmount-disAmount}}</span></p> -->
  57. <p>
  58. 实付金额: {{disAmount}}, 优惠了 :
  59. <span style="color: #ff0000">{{difAmount}}</span>
  60. </p>
  61. </div>
  62. <script>
  63. const app = Vue.createApp({
  64. data() {
  65. return {
  66. price: 10000,
  67. num: 0,
  68. };
  69. },
  70. // 计算属性: 访问器属性
  71. computed: {
  72. payAmount: {
  73. get() {
  74. return this.price * this.num;
  75. },
  76. set(value) {
  77. // 这个通常用来做测试
  78. },
  79. },
  80. },
  81. // 侦听器属性
  82. watch: {
  83. // current: 新值/当前值, origin: 原值/旧值
  84. payAmount(current, origin) {
  85. console.log(current, origin);
  86. switch (true) {
  87. case current > 10000 && current < 20000:
  88. this.disAmount = this.payAmount * 0.99;
  89. break;
  90. case current >= 20000 && current < 30000:
  91. this.disAmount = this.payAmount * 0.98;
  92. break;
  93. case current >= 30000 && current < 40000:
  94. this.disAmount = this.payAmount * 0.97;
  95. case current >= 40000 && current < 50000:
  96. this.disAmount = this.payAmount * 0.96;
  97. break;
  98. case current > 50000:
  99. this.disAmount = this.payAmount * 0.95;
  100. break;
  101. default:
  102. this.disAmount = this.payAmount;
  103. }
  104. this.difAmount = this.payAmount - this.disAmount;
  105. },
  106. },
  107. // 实例生命周期, mounted: 当vue实例加载完成的时候会自动调用(onload)
  108. mounted() {
  109. this.num = 1;
  110. },
  111. }).mount(".app");
  112. </script>
  113. </body>
  114. </html>

[http://help10086.cn/0114/demo5.html]

VUE 组件与组件之间的通信

  • 组件,vue 指令本质是自定义属性
  • vue 组件本质就是自定义标签
  • 子组件传参:自定义属性
  • 监听子组件: $emit(自定义事件, 向父组件传递的参数[可选])
  1. <!-- VUE组件 -->
  2. <!DOCTYPE html>
  3. <html lang="zh-CN">
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  8. <title>组件:全局组件</title>
  9. <script src="https://unpkg.com/vue@next"></script>
  10. </head>
  11. <body>
  12. <div class="app">
  13. <!-- vue指令 -> 自定义属性 -->
  14. <div v-text="'hello'"></div>
  15. <!-- vue组件 -> 自定义标签 -->
  16. <button-counter></button-counter>
  17. </div>
  18. <template id="counter">
  19. <button @click="count++">点赞: {{count}}</button>
  20. </template>
  21. <script>
  22. // 1. 创建实例
  23. const app = Vue.createApp({});
  24. // 2. 注册组件
  25. app.component("ButtonCounter", {
  26. template: "#counter",
  27. data() {
  28. return {
  29. count: 0,
  30. };
  31. },
  32. });
  33. // 3. 绑定挂载点
  34. app.mount(".app");
  35. </script>
  36. </body>
  37. </html>
  38. <!-- 子组件传参 -->
  39. <!DOCTYPE html>
  40. <html lang="zh-CN">
  41. <head>
  42. <meta charset="UTF-8" />
  43. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  44. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  45. <title>子组件传参</title>
  46. <script src="https://unpkg.com/vue@next"></script>
  47. </head>
  48. <body>
  49. <div class="app">
  50. <button-counter username="admin" email="admin@qq.com"></button-counter>
  51. </div>
  52. <template id="counter">
  53. <button @click="count++">点赞: {{count}}</button>
  54. <p>用户: {{username}}</p>
  55. <p>邮箱: {{email}}</p>
  56. </template>
  57. <script>
  58. // 1. 创建实例
  59. const app = Vue.createApp({});
  60. // 2. 注册组件
  61. app.component("ButtonCounter", {
  62. // 自定义属性
  63. props: ["username", "email"],
  64. template: "#counter",
  65. data() {
  66. return {
  67. count: 0,
  68. };
  69. },
  70. });
  71. // 3. 绑定挂载点
  72. app.mount(".app");
  73. </script>
  74. </body>
  75. </html>
  76. <!-- 监听子组件事件 -->
  77. <!DOCTYPE html>
  78. <html lang="zh-CN">
  79. <head>
  80. <meta charset="UTF-8" />
  81. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  82. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  83. <title>监听子组件事件</title>
  84. <script src="https://unpkg.com/vue@next"></script>
  85. </head>
  86. <body>
  87. <div class="app">
  88. <button-counter
  89. username="help"
  90. email="help10086@foxmail.com"
  91. @review-count="review"
  92. ></button-counter>
  93. </div>
  94. <template id="counter">
  95. <button @click="count++">点赞: {{count}}</button>
  96. <p>用户: {{username}}</p>
  97. <p>邮箱: {{email}}</p>
  98. <!-- 发布订阅 -->
  99. <!-- $emit(自定义事件, 向父组件传递的参数[可选]) -->
  100. <button @click="$emit('reviewCount', this.count)">评价</button>
  101. </template>
  102. <script>
  103. // 1. 创建实例
  104. const app = Vue.createApp({
  105. methods: {
  106. review(count) {
  107. console.log(count);
  108. if (count >= 20) {
  109. alert("感谢家人的支持!");
  110. }
  111. },
  112. },
  113. });
  114. // 2. 注册组件
  115. app.component("ButtonCounter", {
  116. props: ["username", "email"],
  117. template: "#counter",
  118. data() {
  119. return {
  120. count: 0,
  121. };
  122. },
  123. });
  124. // 3. 绑定挂载点
  125. app.mount(".app");
  126. // 1. 向子组传传参: props: [....]
  127. // 2. 子组件向父组通信:
  128. // 2.1 子组件: $emit(customEvent, ...args)
  129. // 2.2 父组件: @customEvent(...args)
  130. </script>
  131. </body>
  132. </html>

[http://help10086.cn/0114/demo7.html]
[http://help10086.cn/0114/demo8.html]