1. 基本框架,

  1. <div id="app">
  2. <cpn :number1="num1" :number2="num2"></cpn>
  3. </div>
  4. <template id="cpn">
  5. <div>
  6. <h2>{{number1}}</h2>
  7. <input type="text" v-model>
  8. <h2>{{number2}}</h2>
  9. <input type="text" v-model>
  10. </div>
  11. </template>
  12. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
  13. <script type="text/javascript">
  14. const app = new Vue({
  15. el: '#app',
  16. data: {
  17. num1: 1,
  18. num2: 2
  19. },
  20. components: {
  21. cpn: {
  22. template: "#cpn",
  23. props: {
  24. number1: Number,
  25. number2: Number
  26. }
  27. }
  28. }
  29. })
  30. </script>
  • 需求:通过 input 输入内容,改变 实例的 num1, num2 以及子组件的 number1, number2的值

image.png

  1. <template id="cpn">
  2. <div>
  3. <h2>{{number1}}</h2>
  4. <input type="text" v-model="number1">
  5. <h2>{{number2}}</h2>
  6. <input type="text" v-model="number2">
  7. </div>
  8. </template>
  • 之间将 input的 v-model 进行绑定到 number1 number2 中,则会报错

    Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. 避免直接改变属性,因为每当父组件重新渲染时,该值将被覆盖。相反,使用基于属性值的数据或计算属性。

修改如下:

  1. <div id="app">
  2. <cpn :number1="num1" :number2="num2"></cpn>
  3. </div>
  4. <template id="cpn">
  5. <div>
  6. <h2>props: {{number1}}</h2>
  7. <h2>data: {{dnumber1}}</h2>
  8. <input type="text" v-model="dnumber1">
  9. <h2>props: {{number2}}</h2>
  10. <h2>data: {{dnumber2}}</h2>
  11. <input type="text" v-model="dnumber2">
  12. </div>
  13. </template>
  14. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
  15. <script type="text/javascript">
  16. const app = new Vue({
  17. el: '#app',
  18. data: {
  19. num1: 1,
  20. num2: 2
  21. },
  22. components: {
  23. cpn: {
  24. template: "#cpn",
  25. props: {
  26. number1: Number,
  27. number2: Number
  28. },
  29. data() {
  30. return {
  31. dnumber1: this.number1,
  32. dnumber2: this.number2
  33. }
  34. }
  35. }
  36. }
  37. })
  38. </script>
  • 可以将 input 中的 v-model 换成 :value="dnumber1" @input="dnumber1 = $event.target.value"

保持数据流是单向的,所以子组件不能修改父组件的数据

  1. <div id="app">
  2. <cpn :number1="num1"
  3. :number2="num2"
  4. @num1change="num1change"
  5. @num2change="num2change"></cpn>
  6. </div>
  7. <template id="cpn">
  8. <div>
  9. <h2>props: {{number1}}</h2>
  10. <h2>data: {{dnumber1}}</h2>
  11. <input type="text" :value="dnumber1" @input="num1Input">
  12. <h2>props: {{number2}}</h2>
  13. <h2>data: {{dnumber2}}</h2>
  14. <input type="text" :value="dnumber2" @input="num2Input">
  15. </div>
  16. </template>
  17. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
  18. <script type="text/javascript">
  19. const app = new Vue({
  20. el: '#app',
  21. data: {
  22. num1: 1,
  23. num2: 2
  24. },
  25. methods: {
  26. num1change(value) {
  27. this.num1 = value;
  28. },
  29. num2change(value) {
  30. this.num2 = value;
  31. }
  32. },
  33. components: {
  34. cpn: {
  35. template: "#cpn",
  36. props: {
  37. number1: Number,
  38. number2: Number
  39. },
  40. data() {
  41. return {
  42. dnumber1: this.number1,
  43. dnumber2: this.number2
  44. }
  45. },
  46. methods: {
  47. num1Input(event) {
  48. this.dnumber1 = event.target.value;
  49. this.$emit('num1change', this.dnumber1)
  50. },
  51. num2Input(event) {
  52. this.dnumber2 = event.target.value;
  53. this.$emit('num2change', this.dnumber2)
  54. }
  55. }
  56. }
  57. }
  58. })
  59. </script>
  • 这样可以通过input,进行修改 dnumber 的值,通过 子传父 事件$emit 发送到父组件,父组件通过 numchange进行修改 num的值

  • 默认情况下,emit 传的参数类型为 string 类型

    1. methods: {
    2. num1change(value) {
    3. // console.log(typeof value) //value 是字符串类型
    4. this.num1 = parseFloat(value); //parseInt 将 value转为 float类型
    5. },
    6. num2change(value) {
    7. this.num2 = parseFloat(value);
    8. }
    9. },

2. 完整代码

需求: 通过 input 输入内容,改变 实例的 num1, num2 以及子组件的 number1, number2的值

image.png

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <div id="app">
  9. <cpn :number1="num1"
  10. :number2="num2"
  11. @num1change="num1change"
  12. @num2change="num2change"></cpn>
  13. </div>
  14. <template id="cpn">
  15. <div>
  16. <h2>props: {{number1}}</h2>
  17. <h2>data: {{dnumber1}}</h2>
  18. <input type="text" :value="dnumber1" @input="num1Input">
  19. <h2>props: {{number2}}</h2>
  20. <h2>data: {{dnumber2}}</h2>
  21. <input type="text" :value="dnumber2" @input="num2Input">
  22. </div>
  23. </template>
  24. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
  25. <script type="text/javascript">
  26. const app = new Vue({
  27. el: '#app',
  28. data: {
  29. num1: 1,
  30. num2: 2
  31. },
  32. methods: {
  33. num1change(value) {
  34. // console.log(typeof value) //value 是字符串类型
  35. this.num1 = parseFloat(value); //parseInt 将 value转为float类型
  36. },
  37. num2change(value) {
  38. this.num2 = parseFloat(value);
  39. }
  40. },
  41. components: {
  42. cpn: {
  43. template: "#cpn",
  44. props: {
  45. number1: Number,
  46. number2: Number
  47. },
  48. data() {
  49. return {
  50. dnumber1: this.number1,
  51. dnumber2: this.number2
  52. }
  53. },
  54. methods: {
  55. num1Input(event) {
  56. this.dnumber1 = event.target.value;
  57. this.$emit('num1change', this.dnumber1)
  58. },
  59. num2Input(event) {
  60. this.dnumber2 = event.target.value;
  61. this.$emit('num2change', this.dnumber2)
  62. }
  63. }
  64. }
  65. }
  66. })
  67. </script>
  68. </body>
  69. </html>

3. 扩展

在上面的情况下,下面的number 为上面的 number的 100倍。

  1. methods: {
  2. num1Input(event) {
  3. //1. 将 input中 value赋值到 dnumber中
  4. this.dnumber1 = event.target.value;
  5. //2.为了父组件可以修改值,发出一个事件
  6. this.$emit('num1change', this.dnumber1)
  7. //3. 同时修改 dnumber的值
  8. this.dnumber2 = this.dnumber1 * 100;
  9. this.$emit('num2change', this.dnumber2)
  10. },
  11. num2Input(event) {
  12. this.dnumber2 = event.target.value;
  13. this.$emit('num2change', this.dnumber2)
  14. this.dnumber1 = this.dnumber2 / 100;
  15. this.$emit('num1change', this.dnumber1)
  16. }
  17. }

4. watch 实现

侦听器:watch 官方文档

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <div id="app">
  9. <cpn :number1="num1"
  10. :number2="num2"
  11. @num1change="num1change"
  12. @num2change="num2change"></cpn>
  13. </div>
  14. <template id="cpn">
  15. <div>
  16. <h2>props: {{number1}}</h2>
  17. <h2>data: {{dnumber1}}</h2>
  18. <input type="text" v-model="dnumber1">
  19. <h2>props: {{number2}}</h2>
  20. <h2>data: {{dnumber2}}</h2>
  21. <input type="text" v-model="dnumber2">
  22. </div>
  23. </template>
  24. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
  25. <script type="text/javascript">
  26. const app = new Vue({
  27. el: '#app',
  28. data: {
  29. num1: 1,
  30. num2: 2
  31. },
  32. methods: {
  33. num1change(value) {
  34. // console.log(typeof value) //value 是字符串类型
  35. this.num1 = parseFloat(value); //parseInt 将 value转为float类型
  36. },
  37. num2change(value) {
  38. this.num2 = parseFloat(value);
  39. }
  40. },
  41. components: {
  42. cpn: {
  43. template: "#cpn",
  44. props: {
  45. number1: Number,
  46. number2: Number
  47. },
  48. data() {
  49. return {
  50. dnumber1: this.number1,
  51. dnumber2: this.number2
  52. }
  53. },
  54. watch: {
  55. dnumber1(newValue) {
  56. this.dnumber2 = newValue * 100;
  57. //改变Vue实例中的值,通过props改变number1
  58. this.$emit("num1change", newValue);
  59. },
  60. dnumber2(newValue) {
  61. this.dnumber1 = newValue / 100;
  62. this.$emit("num2change", newValue)
  63. }
  64. }
  65. }
  66. }
  67. })
  68. </script>
  69. </body>
  70. </html>