Vue框架 - 组件之间如何通信及props属性的那点事儿

组件通话 插槽 及 props属性

上一篇博客中已经介绍了 Vue 组件的一些基础 及 单项的数据传递,在实际的使用中,往往需要做到数据的双向传递。
这篇博客主要是介绍 实现数据双向传递的方法。

数据双向传递

方法一

将之前的单项数据传递的方法结合起来使用

  • 父传子
    父组件通过 :自定义属性名="想要传递的数据" 的方式,将自身的数据绑给子组件标签
    子组件通过 props:["相同的自定义属性名"] 的方式接收数据,使用方法和data数据的方法一致
  • 子传父
    子组件通过事件触发方法,在触发的方法中自定义监听事件及传递的数据 this.$emit("自定义监听事件",想要传递的数据)
    父组件通过 @子组件的自定义监听事件="新的方法名" 的方式,获取到传递的数据,自行决定是否使用
    <div id="app">
        <test-div :emm="name" @gg="fn"></test-div>
        <span>子组件的回传数据:{{text}}</span> 
    </div>
    <script>
        Vue.component("test-div",{
            template:`
                

接收的父组件数据:{{emm}}

`
, props:["emm"], data:function(){ return { name:"子组件", text:"测试数据" } }, methods:{ go(){ console.log(11) this.$emit("gg",this.name) } } }) let app = new Vue({ el:"#app", data:{ name:`我来自父组件`, text:"父组件测试数据" }, methods:{ fn(n){ console.log(n) this.text = n; } } }); </script>
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第1张图片
方法二

v-model 实现

  • 父传子
    与第一种方法的方式一致,只是绑定数据的时候使用 v-model
  • 子传父
    仍需要使用 this.$emit( ) 来自定义事件,但是需要使用model属性来保存,
    同时舍去了 父组件绑定监听事件的步骤
    • prop 告诉 v-model 绑定的 prop 是哪个
    • event 告诉 v-model 触发指定事件时
      自动去修改绑定的值 是哪个( 与 this.$emit( ) 中的自定义事件一致 )
    <div id="app">
        <test-p v-model="data2"></test-p>
        <hr/>
        <p>父组件{{data2}}</p>
    </div>

    <script>
        Vue.component("test-p",{
            props:["emm","data2"],
            model:{
                //  prop 告诉 v-model 绑定的 prop 是哪个
                prop:"data2",
                
                // event 告诉 v-model 触发指定事件时
                //  自动去修改绑定的值
                event:"back" // 封装的了监听和回调,以及赋值
            },
            data:function(){
                return {
                    name:"子数据",
                    text:"测试数据",
                }
            },
            template:`
                
{{text}}

子组件的数据:{{data2}}

`
, methods:{ went(){ // console.log(11) this.$emit("back",this.name) } } }) let app = new Vue({ el:"#app", data:{ name:`我来自父组件`, text:"父组件测试数据", data2:"双向数据2" }, methods:{ fn(n){ console.log(n) this.text = n; } } }); </script>
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第2张图片
方法三

.sync 实现

  • 父传子
    父组件使用 :自定义变量名="传递数据"的方式传递数据给子组件
    子组件使用 props:["自定义变量名"] 方式的接收数据
  • 子传父
    父组件要传递的数据添加 .sync 格式为:自定义名称.sync="传递数据"
    子组件使用回传的数据添加 update: 格式为this.$emit("update:自定义名称",回传数据)
    父、子组件的自定义名称一致
	<div id="app">
		<my-try :nowpage.sync="uPage" > </my-try>
		<div>{{uPage}}</div>
	</div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        // 测试说明 .sync 使用
        Vue.component("my-try",{
            props:["nowpage"],
            template:` 
                
`
, methods:{ test(){ // console.log("测试数据启用"); console.log("当前第"+this.nowpage+"页"); this.$emit("update:nowpage",this.nowpage +1); } } }) let app = new Vue({ el: '#app', data: { uPage: 1, } });
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第3张图片

插槽 slot

组件模板解析后会替换整个组件内容,( 原先写在页面上所有内容都会被覆盖 )
改善了修改组件内容,需要去组件内部的操作的繁琐步骤
相当于在组件上留下接口,便于后续增添内容

插槽调用

使用内置组件 templatev-slot 指令进行配置

  • 组件内部的插槽设置开启
	Vue.component("page-div", {
		template: `
			
写什么不重要,反正不实现
`
, })
  • 页面结构的插槽调用
    通过属性 slot 来实现
	<div id="app">
        <page-div>
            <span slot="default">默认插槽span>
        page-div>
    div>
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第4张图片
插槽分类

默认插槽
上述的方法即为 默认插槽 的实现
具名插槽
通过设置 name 属性实现,例:
调用的时候 通过 template 标签添加 v-slot:name名='数据' 实现

  • 组件插槽设置
	Vue.component("page-div", {
		template: `
			
1234
`
, })
  • 页面结构的插槽调用
    调用之后就会覆盖,组件内插槽的内容
	<div id="app">
        <page-div>
            <template v-slot:all="{all}">
            	<a class="tj" >共……页a>
            template>
        page-div>
    div>
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第5张图片
插槽传参

其实已经在具名插槽时实现了
template 标签添加 v-slot:name名='数据' 实现数据传递
只是传递的 数据类型为对象形式,需要解构赋值或者通过点语法使用

    <div id="app">
        <page-div @get-data="play" :txt="default_page" :total="allpages">
            <template v-slot:now="props" > 
                
                
                <a class="tj">第{{props.now}}页a>
            template>
            <template v-slot:all="{all}">
                
                <a class="tj" >共{{all}}页a>
            template>
        page-div>
    div>

    <script>
        Vue.component("page-div", {
            props: ["txt", "total"],
            template: `
                
            `,
            // 维持数据的独立性 
            data: function () {
                return {
                    users: [
                        { id: 1, name: "兰博", talk: "谁说我是小个子" },
                        { id: 2, name: "鑫涛", talk: "我是最强壮的男人" },
                        { id: 3, name: "光达", talk: "对对对,是是是" },    
                        { id: 4, name: "宝峰", talk: "我尼玛人都傻了" },
                        { id: 5, name: "祥子", talk: "那必不可能是那样" },
                        { id: 6, name: "亚托克斯", talk: "我是噬神者" },
                        { id: 7, name: "女警", talk: "砰,脑洞!" },
                        { id: 8, name: "洛", talk: "是谁在那儿?!" },
                        { id: 9, name: "锤石", talk: "出来玩玩?" },
                        { id: 10, name: "秦兟", talk: "?!……" },
                    ],
                    perpage: 3,
                    nowpage: 1
                }
            },
            computed: {
                showUsers: {
                    get() {
                        return JSON.parse(JSON.stringify(this.users)).splice((this.nowpage - 1) * this.perpage, this.perpage)
                    }
                },
                pages() {
                    return Math.ceil(this.users.length / this.perpage)
                }
            },
            methods: {
                goOn(p) {
                    this.nowpage = p;
                    let obj = {
                        page: this.nowpage,
                        data: this.showUsers,
                        all: this.pages
                    }
                    this.$emit("get-data", obj);
                }
            }
        })

        let app = new Vue({
            el: "#app",
            data: {
                users: [
                    { id: 1, name: "兰博", talk: "谁说我是小个子" },
                    { id: 2, name: "鑫涛", talk: "我是最强壮的男人" },
                    { id: 3, name: "光达", talk: "对对对,是是是" },
                ],
                default_page: 1,
                allpages:"…"
            },
            methods: {
                play: function (v) {
                    this.users = v.data;
                    this.default_page = v.page;
                    this.allpages = v.all;
                }
            }
        });
    script>

props 的那点事儿

非 prop特性

是指数据传向一个组件,但是该组件并没有相应 prop 定义的特性
这些 props 会被自动添加到组件的根元素上
可以通过this.$attrs.属性名调用

  • 父组件传参
	<div id="app">
        
        <k-div :myname="name" :mypage="pages" :mytry="text"> k-div>
    div>
  • 子组件不接收,通过this.$attrs.属性名直接使用
	Vue.component("k-div",{
		// props: 没有接收 mypage 非 常规操作
		//  mypage会出现在 this.$attrs 中 (即 根元素上)
		props:["myname"],
		inheritAttrs:false, // 默认是 true 处理 子组件继承的问题
		template:`
			
props没接收的数据 mypage{{this.$attrs.mypage}}
`
, data:function(){ return { name:`kids`, mypage:"hello,我在这" } }, methods:{ getData(){ console.log(this.$attrs) } } })
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第6张图片
props 验证

适用于检查数据类型的场景,
不符合的情况下,会提示错误信息,但不会阻断程序运行

  • 父组件传递数据
    <div id="app">
        <k-div :msg="pages"> k-div>
    div>
	<script>
        let app = new Vue({
            el:"#app",
            data:{
                text:"测试文本信息",
                pages:20
            }
        });
    script>
  • 子组件只验证数据类型
	Vue.component("k-div",{
    	props:{
	        // 验证传递的数据类型
	        // 不满足数据类型时,会报错只是不会阻断运行
	        msg:[String]
    	},
    	template:`
    		

测试而已{{msg}}

`
})
  • 页面效果
    Vue框架 - 组件之间如何通信及props属性的那点事儿_第7张图片

你可能感兴趣的:(vue)