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

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

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

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

<body>
    <div id="vueBox">
        <p>{{num}}</p>
        <button v-on:click="add">添加</button>
    </div>
</body>

<script type="text/javascript">

    var vue = new Vue({
        el: "#vueBox",
        data: {
            num: 0
        },
        methods: {
           add: function() {
               this.num++;
           }
        },
        watch: {
            num: function(newValue, oldValue) {
                console.log("新值:"+newValue);
                console.log("旧值:"+oldValue);
            }
        }

    })

</script>

2. 组件创建 - component

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

语法特点:

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

你好

按钮"

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

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

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

<body>
    <div id="vueBox">
        <my_component></my_component>
        <my_component></my_component>        
    </div>
</body>

<script type="text/javascript">

   Vue.component("my_component", {
       template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
       data() {
           return {
               num:0
           }
       },
       methods: {
           add: function() {
               this.num++;
           }
       }
   })

    var vue = new Vue({
        el: "#vueBox"
    })

</script>

2.2 局部组件

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

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

<body>
    <div id="vueBox">
        <my_component></my_component>
        <my_component></my_component>
    </div>
</body>

<script type="text/javascript">

   const myComponent = {
       template: "<div><p>数字:{{num}}</p><button v-on:click='add'>添加</button></div>",
       data() {
           return {
               num:0
           }
       },
       methods: {
           add: function() {
               this.num++;
           }
       }
   }

    var vue = new Vue({
        el: "#vueBox",
        components: {
            my_component: myComponent
        }
    })

</script>

3 组件间的通信

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

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

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

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

<body>
<div id="vueBox">
    <my_component v-bind:content="conten1"></my_component>
    <my_component :content="content1"></my_component>
    <button v-on:click="add">父组件按钮增加</button>
</div>
</body>

<script type="text/javascript">

    Vue.component("my_component", {
        template: "<div><p>数字:{{content}}</p><button v-on:click='chang'>字组件按钮增加</button></div>",
        props: ["content"],
        methods: {
            chang: function() {
                this.content++
            }
        }
    })

    var vue = new Vue({
        el: "#vueBox",
        data: {
            content1: 10
        },
        methods: {
          add: function(){
              this.content1++
          }
        }

    })

</script>

执行流程

语法注意

  1. $emit( 自定义事件名,传参 ) - 自定义组件的事件名
  2. @组件事件名=‘父组件的方法’ - 触发方法
  3. $event接收 $emit()的参数值
<body>
    <div id="vueBox">
        <p>{{num}}</p>
       <my-tag @my-add-event="fatherAdd($event)"></my-tag>
    </div>
</body>

<script type="text/javascript">

    Vue.component("my-tag", {
        template: "<p><button v-on:click='add'>数字增加</button></p>",
        methods: {
            add: function() {
                this.$emit("my-add-event", 10)
            }
        }
    })

    var vue = new Vue({
        el: "#vueBox",
        data: {
            num: 1
        },
        methods: {
            fatherAdd: function(val) {
                this.num = this.num +val;
            }
        }

    })

</script>

3.1.2 静态绑定
<body>
    <div id="vueBox">
       <my-tag title="父组件传来的字面量"></my-tag>
       <my-tag></my-tag>
    </div>
</body>

<script type="text/javascript">

    Vue.component("my-tag", {
        template: "<p>{{msg}}--{{title}}</p>",
        data: function(){
            return {msg: '组件的内置数据'}
        },
        props: {
            title: {
                type: String,
                default: "预设的值"
            }
        }

    })

    var vue = new Vue({
        el: "#vueBox",
        data: {
            nums: [1,2,3,4]
        }
       
    })

</script>

注意:

  1. v-bind:props属性名:"" – 会自动转对应的数据类型
  2. props属性名:"" – 全局都为字符串String类型数据
<body>
    <div id="vueBox">
       <my-tag msg1="200" :msg2="200"></my-tag>
    </div>
</body>

<script type="text/javascript">

    Vue.component("my-tag", {
        template: "<p>{{typeof msg1}} -- {{typeof msg2 }}</p>",

        props: ["msg1", "msg2"]

    })

    var vue = new Vue({
        el: "#vueBox",
        data: {
        }

    })

</script>

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

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

  1. 在组件改变父组件属性的时候,必须使用this.$emit(“自定义事件名”) - 发出一个事件出去
  2. 并且在绑定函数时 @事件名=“父组件处理函数名” – 父组件对事件相应的处理
<body>
    <div id="vueBox">

        <p>父组件num:{{num}}</p>
        <my_component :num1="num" @add="add" @reduce="reduce" ></my_component>
    </div>
</body>

<script type="text/javascript">

    Vue.component("my_component", {

        template: "<div><p>子组件num1:{{num1}}</p><button v-on:click='add'>增加</button><button v-on:click='reduce'>减少</button></div>",

        props: ["num1"],
        methods: {
            add: function() {
                this.$emit("add");
            },
            reduce: function() {
                this.$emit("reduce");
            }
        }
    })

    var vue = new Vue({

        el: "#vueBox",
        data: {
            num : 0
        },
        methods: {
            add: function() {
                this.num++;
            },
            reduce: function() {
                this.num--;
            }
        }

    })

</script>

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

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

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

<div id="vueBox">
    <button v-on:click="destoryMsg">销魂两兄弟组件的信息交互</button>
    <my-tag1></my-tag1>
    <my-tag2></my-tag2>

</div>
</body>

<script type="text/javascript">

    // 信息中心 - 媒介
    var msgCenter = new Vue();

    Vue.component("my-tag1", {
        template: "<div><p>tag1的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
        data: function () {
            return {
                num: 0
            }
        },
        methods: {
            handle: function () {
                // 向信息中心发送tag1-event事件
                msgCenter.$emit("tag1-event", 20)
            }
        },
        mounted: function () {
            // 信息中心在这里进行执行监听tag2-event事件
            msgCenter.$on("tag2-event", (val) => {
                this.num = this.num + val;
            })
        }
    })

    Vue.component("my-tag2", {
        template: "<div><p>tag2的num:{{num}}</p><button v-on:click='handle'>数字增加</button></div>",
        data: function () {
            return {
                num: 0
            }
        },
        methods: {
            handle: function () {
                msgCenter.$emit("tag2-event", 10)
            }
        },
        mounted: function () {
            msgCenter.$on("tag1-event", (val) => {
                this.num = this.num + val;
            })
        }
    })

    var vue = new Vue({
        el: "#vueBox",
        methods: {
            destoryMsg: function () {
                msgCenter.$off("tag1-event");
                msgCenter.$off("tag2-event");
            }
        }
    })

</script>

4 组件的插槽 - slot

4.1 无名插槽

父组件向子组件传递内容

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

<head>
    <meta charset="UTF-8">
    <title>Vue测试</title>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <style>
    </style>
</head>
<body>
    <div id="vueBox">
        <my-component><a>你很丑</a></my-component>
        <my-component><a>太矮了</a></my-component>
        <my-component></my-component>
    </div>
</body>

<script type="text/javascript">

   Vue.component("my-component",{
       template: `
            <div>
                <span style="color:red">错误提示:</span>
                <slot><a>默认内容</a></slot>
            </div>`,
   })

    var vue = new Vue({
        el: "#vueBox"
    })

</script>

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

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

<body>
    <div id="vueBox">
       <my-component>
            <span>填入无名插槽</span>
            <span slot="name1">填入name1插槽</span>
            <span slot="name2">填入name2无名插槽</span>
       </my-component>
    </div>
</body>

<script type="text/javascript">

   Vue.component("my-component",{
       template: `
            <div>
                <span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
                <br/>

                <span style="color:red">错误提示:</span><slot name="name1"></slot>
                <br/>

                <span style="color:red">错误提示:</span><slot name="name2"></slot>
                <br/>
            </div>`,
   })

    var vue = new Vue({
        el: "#vueBox"
    })

</script>

4.2.2 使用标签
<body>
    <div id="vueBox">
       <my-component>
           <template>
               <span>填入无名插槽</span>
           </template>
           
           <template slot="name1">
               <span >填入name1插槽</span>
           </template>
           
           <template slot="name2">
               <span >填入name2无名插槽</span>
           </template>
       </my-component>
    </div>
</body>

<script type="text/javascript">

   Vue.component("my-component",{
       template: `
            <div>
                <span style="color:red">错误提示:</span><slot><a>默认内容无名插槽</a></slot>
                <br/>

                <span style="color:red">错误提示:</span><slot name="name1"></slot>
                <br/>

                <span style="color:red">错误提示:</span><slot name="name2"></slot>
                <br/>
            </div>`,
   })

    var vue = new Vue({
        el: "#vueBox"
    })

</script>

4.3 作用域插槽

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

下列示例的数据流动图片

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

<body>
    <div id="vueBox" >
       <my-component v-bind:students="students">
           <template slot-scope="args">
                <span v-if="args.msg.id == 2" style="color:red">{{args.msg.name}}</span>
                <span v-else>{{args.msg.name}}</span>
           </template>

       </my-component>
    </div>
</body>

<script type="text/javascript">

   Vue.component("my-component",{
       template: `
            <ul>
                <li v-for="student in students"><slot :msg="student"></slot></li>
            </ul>
       `,
       props:["students"]

   })

    var vue = new Vue({
        el: "#vueBox",
        data: {
            students: [{
                id: 1,
                name: 'lrc'
            },{
                id: 2,
                name: 'lcj'
            },{
                id: 3,
                name: 'yxx'
            }]
        }
    })

</script>

相关文章