Vue学习3 - 属性值的监控watch、组件的创建、组件间的通信、插槽

x33g5p2x  于2022-02-12 转载在 Vue.js  
字(9.8k)|赞(0)|评价(0)|浏览(687)

1. 监听属性值的变化 - watch

语法要求:watch里面的函数名必须跟date里面属性名一致

  1. <body>
  2. <div id="vueBox">
  3. <p>{{num}}</p>
  4. <button v-on:click="add">添加</button>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. var vue = new Vue({
  9. el: "#vueBox",
  10. data: {
  11. num: 0
  12. },
  13. methods: {
  14. add: function() {
  15. this.num++;
  16. }
  17. },
  18. watch: {
  19. num: function(newValue, oldValue) {
  20. console.log("新值:"+newValue);
  21. console.log("旧值:"+oldValue);
  22. }
  23. }
  24. })
  25. </script>

2. 组件创建 - component

**作用:**相同的部分提取出来,通过包含技术,实现避免重复内容的编写 – 即共享代码

语法特点:

  1. 该vue对象的定义差不多,区别就是date属性变成函数date()
  2. 使用时直接<组件名></组件名>即可
  3. 组件名不可使用驼峰命名法,如果下划线_进行区分单词含义
  4. 注意:template里面的节点只能有一个祖宗,否则丢失一个祖宗(单个根元素)
    不可写成template:"

你好

按钮"

  1. 语法:templates属性可以是字符串可以是模板内容
  1. Vue.component("my-tag",{
  2. template: "<div></div>" --字符串
  3. template:`<div></div>` --模板字符串
  4. })
2.1 全局组件

全局组件内部可以引用全局组件

特点:组件一旦全局注册,即使整个项目没有使用该组件,依然会随者Vue的加载而加载组件复用时,是相互独立,相同的组件间不会受彼此影响

  1. <body>
  2. <div id="vueBox">
  3. <my_component></my_component>
  4. <my_component></my_component>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. Vue.component("my_component", {
  9. template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
  10. data() {
  11. return {
  12. num:0
  13. }
  14. },
  15. methods: {
  16. add: function() {
  17. this.num++;
  18. }
  19. }
  20. })
  21. var vue = new Vue({
  22. el: "#vueBox"
  23. })
  24. </script>

2.2 局部组件

局部组件内部不可以引用局部组件

特点: 对于不频繁使用的组件,则将其定义在Vue实例里面 - 成为Vue实例一个子集

  1. <body>
  2. <div id="vueBox">
  3. <my_component></my_component>
  4. <my_component></my_component>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. const myComponent = {
  9. template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
  10. data() {
  11. return {
  12. num:0
  13. }
  14. },
  15. methods: {
  16. add: function() {
  17. this.num++;
  18. }
  19. }
  20. }
  21. var vue = new Vue({
  22. el: "#vueBox",
  23. components: {
  24. my_component: myComponent
  25. }
  26. })
  27. </script>

3 组件间的通信

如果一个单页面以组件形式构成,则能刻画成一颗多节点的树

3.1 父向子组件传递数据 - props
3.1.1 动态绑定

注意父组件传递的值只会起效第一次,子组件改变属性值并不会影响父组件,父组件属性值改变并不影响子组件属性值

v-bind:子属性=“父属性” 等价于 :子属性="父属性"

  1. <body>
  2. <div id="vueBox">
  3. <my_component v-bind:content="conten1"></my_component>
  4. <my_component :content="content1"></my_component>
  5. <button v-on:click="add">父组件按钮增加</button>
  6. </div>
  7. </body>
  8. <script type="text/javascript">
  9. Vue.component("my_component", {
  10. template: "<div><p>数字:{{content}}</p><button v-on:click='chang'>字组件按钮增加</button></div>",
  11. props: ["content"],
  12. methods: {
  13. chang: function() {
  14. this.content++
  15. }
  16. }
  17. })
  18. var vue = new Vue({
  19. el: "#vueBox",
  20. data: {
  21. content1: 10
  22. },
  23. methods: {
  24. add: function(){
  25. this.content1++
  26. }
  27. }
  28. })
  29. </script>

执行流程

语法注意

  1. $emit( 自定义事件名,传参 ) - 自定义组件的事件名
  2. @组件事件名=‘父组件的方法’ - 触发方法
  3. $event接收 $emit()的参数值
  1. <body>
  2. <div id="vueBox">
  3. <p>{{num}}</p>
  4. <my-tag @my-add-event="fatherAdd($event)"></my-tag>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. Vue.component("my-tag", {
  9. template: "<p><button v-on:click='add'>数字增加</button></p>",
  10. methods: {
  11. add: function() {
  12. this.$emit("my-add-event", 10)
  13. }
  14. }
  15. })
  16. var vue = new Vue({
  17. el: "#vueBox",
  18. data: {
  19. num: 1
  20. },
  21. methods: {
  22. fatherAdd: function(val) {
  23. this.num = this.num +val;
  24. }
  25. }
  26. })
  27. </script>

3.1.2 静态绑定
  1. <body>
  2. <div id="vueBox">
  3. <my-tag title="父组件传来的字面量"></my-tag>
  4. <my-tag></my-tag>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. Vue.component("my-tag", {
  9. template: "<p>{{msg}}--{{title}}</p>",
  10. data: function(){
  11. return {msg: '组件的内置数据'}
  12. },
  13. props: {
  14. title: {
  15. type: String,
  16. default: "预设的值"
  17. }
  18. }
  19. })
  20. var vue = new Vue({
  21. el: "#vueBox",
  22. data: {
  23. nums: [1,2,3,4]
  24. }
  25. })
  26. </script>

注意:

  1. v-bind:props属性名:"" – 会自动转对应的数据类型
  2. props属性名:"" – 全局都为字符串String类型数据
  1. <body>
  2. <div id="vueBox">
  3. <my-tag msg1="200" :msg2="200"></my-tag>
  4. </div>
  5. </body>
  6. <script type="text/javascript">
  7. Vue.component("my-tag", {
  8. template: "<p>{{typeof msg1}} -- {{typeof msg2 }}</p>",
  9. props: ["msg1", "msg2"]
  10. })
  11. var vue = new Vue({
  12. el: "#vueBox",
  13. data: {
  14. }
  15. })
  16. </script>

3.2 子向父组件传递数据 - v-bind:属性绑定

数据传递原则: 单向数据流原则,尽量少的子组件改变父组件的数据

  1. 在组件改变父组件属性的时候,必须使用this.$emit(“自定义事件名”) - 发出一个事件出去
  2. 并且在绑定函数时 @事件名=“父组件处理函数名” – 父组件对事件相应的处理
  1. <body>
  2. <div id="vueBox">
  3. <p>父组件num:{{num}}</p>
  4. <my_component :num1="num" @add="add" @reduce="reduce" ></my_component>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. Vue.component("my_component", {
  9. template: "<div><p>子组件num1:{{num1}}</p><button v-on:click='add'>增加</button><button v-on:click='reduce'>减少</button></div>",
  10. props: ["num1"],
  11. methods: {
  12. add: function() {
  13. this.$emit("add");
  14. },
  15. reduce: function() {
  16. this.$emit("reduce");
  17. }
  18. }
  19. })
  20. var vue = new Vue({
  21. el: "#vueBox",
  22. data: {
  23. num : 0
  24. },
  25. methods: {
  26. add: function() {
  27. this.num++;
  28. },
  29. reduce: function() {
  30. this.num--;
  31. }
  32. }
  33. })
  34. </script>

3.3 非父子组件间的传递信息

利用中间媒介(事件中心)进行传递

利用一个Vue实例进行做组件间的信息传递

  1. <div id="vueBox">
  2. <button v-on:click="destoryMsg">销魂两兄弟组件的信息交互</button>
  3. <my-tag1></my-tag1>
  4. <my-tag2></my-tag2>
  5. </div>
  6. </body>
  7. <script type="text/javascript">
  8. // 信息中心 - 媒介
  9. var msgCenter = new Vue();
  10. Vue.component("my-tag1", {
  11. template: "<div><p>tag1的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
  12. data: function () {
  13. return {
  14. num: 0
  15. }
  16. },
  17. methods: {
  18. handle: function () {
  19. // 向信息中心发送tag1-event事件
  20. msgCenter.$emit("tag1-event", 20)
  21. }
  22. },
  23. mounted: function () {
  24. // 信息中心在这里进行执行监听tag2-event事件
  25. msgCenter.$on("tag2-event", (val) => {
  26. this.num = this.num + val;
  27. })
  28. }
  29. })
  30. Vue.component("my-tag2", {
  31. template: "<div><p>tag2的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
  32. data: function () {
  33. return {
  34. num: 0
  35. }
  36. },
  37. methods: {
  38. handle: function () {
  39. msgCenter.$emit("tag2-event", 10)
  40. }
  41. },
  42. mounted: function () {
  43. msgCenter.$on("tag1-event", (val) => {
  44. this.num = this.num + val;
  45. })
  46. }
  47. })
  48. var vue = new Vue({
  49. el: "#vueBox",
  50. methods: {
  51. destoryMsg: function () {
  52. msgCenter.$off("tag1-event");
  53. msgCenter.$off("tag2-event");
  54. }
  55. }
  56. })
  57. </script>

4 组件的插槽 - slot

4.1 无名插槽

父组件向子组件传递内容

如果没有标签则自定义组件插入的内容不会显示出来

  1. <head>
  2. <meta charset="UTF-8">
  3. <title>Vue测试</title>
  4. <script src="./node_modules/vue/dist/vue.js"></script>
  5. <style>
  6. </style>
  7. </head>
  8. <body>
  9. <div id="vueBox">
  10. <my-component><a>你很丑</a></my-component>
  11. <my-component><a>太矮了</a></my-component>
  12. <my-component></my-component>
  13. </div>
  14. </body>
  15. <script type="text/javascript">
  16. Vue.component("my-component",{
  17. template: `
  18. <div>
  19. <span style="color:red">错误提示:</span>
  20. <slot><a>默认内容</a></slot>
  21. </div>`,
  22. })
  23. var vue = new Vue({
  24. el: "#vueBox"
  25. })
  26. </script>

4.2 有名插槽 - 意味一个组件可写多个插槽
4.2.1 不使用标签

模版上使用name进行插槽命名,使用slot进行标记插在哪一个槽上

  1. <body>
  2. <div id="vueBox">
  3. <my-component>
  4. <span>填入无名插槽</span>
  5. <span slot="name1">填入name1插槽</span>
  6. <span slot="name2">填入name2无名插槽</span>
  7. </my-component>
  8. </div>
  9. </body>
  10. <script type="text/javascript">
  11. Vue.component("my-component",{
  12. template: `
  13. <div>
  14. <span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
  15. <br/>
  16. <span style="color:red">错误提示:</span><slot name="name1"></slot>
  17. <br/>
  18. <span style="color:red">错误提示:</span><slot name="name2"></slot>
  19. <br/>
  20. </div>`,
  21. })
  22. var vue = new Vue({
  23. el: "#vueBox"
  24. })
  25. </script>

4.2.2 使用标签
  1. <body>
  2. <div id="vueBox">
  3. <my-component>
  4. <template>
  5. <span>填入无名插槽</span>
  6. </template>
  7. <template slot="name1">
  8. <span >填入name1插槽</span>
  9. </template>
  10. <template slot="name2">
  11. <span >填入name2无名插槽</span>
  12. </template>
  13. </my-component>
  14. </div>
  15. </body>
  16. <script type="text/javascript">
  17. Vue.component("my-component",{
  18. template: `
  19. <div>
  20. <span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
  21. <br/>
  22. <span style="color:red">错误提示:</span><slot name="name1"></slot>
  23. <br/>
  24. <span style="color:red">错误提示:</span><slot name="name2"></slot>
  25. <br/>
  26. </div>`,
  27. })
  28. var vue = new Vue({
  29. el: "#vueBox"
  30. })
  31. </script>

4.3 作用域插槽

父组件对子组件内容进行加工处理

下列示例的数据流动图片

vue实例的students数据全局组件的studentsmsg属性args属性

  1. <body>
  2. <div id="vueBox" >
  3. <my-component v-bind:students="students">
  4. <template slot-scope="args">
  5. <span v-if="args.msg.id == 2" style="color:red">{{args.msg.name}}</span>
  6. <span v-else>{{args.msg.name}}</span>
  7. </template>
  8. </my-component>
  9. </div>
  10. </body>
  11. <script type="text/javascript">
  12. Vue.component("my-component",{
  13. template: `
  14. <ul>
  15. <li v-for="student in students"><slot :msg="student"></slot></li>
  16. </ul>
  17. `,
  18. props:["students"]
  19. })
  20. var vue = new Vue({
  21. el: "#vueBox",
  22. data: {
  23. students: [{
  24. id: 1,
  25. name: 'lrc'
  26. },{
  27. id: 2,
  28. name: 'lcj'
  29. },{
  30. id: 3,
  31. name: 'yxx'
  32. }]
  33. }
  34. })
  35. </script>

相关文章