Day10-元件沟通传递(part2)

没有props还可以传资料吗

v-bindv-on在没有props的情况下一样可以得到父层的资料。

<div id="app">
   <my-component :class="className" @click="greeting"></my-component>
</div>
<!--渲染後<div class="card block">Vue</div>--->
const app = Vue.createApp({
    data() {
        return {
            className: 'block'
        }
    },
		methods: {
        greeting() {
            alert('Hi')
        }
    }
});
app.component('my-component', {
    template: `
    <div class="card"></div>
    `,
})
app.mount('#app');

补充:

  1. v-bind="$sttrs"

在多个节点的情况下,Vue找不到DOM就会出现错误,加上v-bind="$sttrs"可以告诉他DOM在哪

app.component('my-component', {
    template: `
        <header>...</header>
        <body v-bind="$sttrs">...</body>
        <footer>...</footer>
    `
})
  1. inheritAttrs: false

不想要子元素继承资料可以加这个。

app.component('my-component', {
		inheritAttrs: false,
    template: `.....`
})

递回元件Recursive Component

子元件中包子元件,常看到的样子就是像树状图那样的结构,如: 侧选单含有次选单。

递回一定要有name属性,不然元件就不能呼叫,呼叫时最好也有:key做为唯一的标签。

Untitled

<div id="app">
        <menu-component :title="menuData.name" :child="menuData.childNodes"></menu-component>
    </div>
const menuData = {
    name: 'uniqlo',
    childNodes: [{
        name: 'women',
        url: null,
        childNodes: [{
            name: 'top',
            url: 'https://www.uniqlo.com/tw/special/outerlineup/women/'
        },
        {
            name: 'inner',
            url: 'https://www.uniqlo.com/tw/store/feature/women/inner/wireless-bra/'
        }]
    },
    {
        name: 'men',
        url: null,
        childNodes: [{
            name: 'top',
            url: 'https://www.uniqlo.com/tw/special/topscollection/men/'
        }, {
            name: 'bottom',
            url: 'https://www.uniqlo.com/tw/special/bottomscollection/men/'
        },
        {
            name: 'shirts',
            url: 'https://www.uniqlo.com/tw/store/feature/men/tops/dress-shirts-long-and-short/'
        }]
    }, {
        name: 'child',
        url: null,
    }
    ]
}
const app = Vue.createApp({
    data() {
        return {
            menuData
        }
    }
});
app.component('menu-component', {
    name: `menu-component`,
    props: {
        title: String,
        url: String,
        child: {
            type: Array,
            default: []
        }
    },
    data() {
        return {
            isOpen: false
        }
    },
    template: `
    <ul>
    <li>
        <template v-if="child.length > 0">
            <h2 class="has-child" :class="{'isOpen':isOpen}" @click="isOpen=!isOpen">{{title}}</h2>
            <menu-component v-show="isOpen" v-for="c in child" :title=c.name :child="c.childNodes" :url="c.url">
            </menu-component>
        </template>
        <a :href="url" v-else>{{title}}</a>
    </li>
</ul>
    `
})
app.mount('#app');

自定义事件

父子元件之间的沟通方式有个流传已久的口诀:「Props in, Event out」。—重新认识 Vue.js

当子元件要将处理过的资料送回外层父元件时,可以透过this.$emit触发@update="updateInfo"来更新外层资料,用下图可以清楚的知道资料的流动。

Untitled

deep
watch里面的参数。我们都知道对象 {} 都指向一个内存地址。当其属性改变的时候,对象的内存地址没发生改变。故当watch监听一个对象的时候,对象属性发生改变,watch监听不到。为了发现对象内部值的变化,可以在选项参数中指定 deep: true 。——Vue.js中的methods,computed,watch。

v-model元件双向绑定

讲到v-model双向绑定元件前要先回顾一下之前的表单绑定,先前在绑定input时会使用v-bind,可以将其拆解为下

<input v-model="msg">
<!-- 拆解 -->
<input v-bind:value="msg" v-on:input="msg=$event.target.value">

使用在元件双向绑定也是类似的概念,component 接收一个 modelValue 的值,然後透过触发 update:modelValue 事件来更新值。

<my-component v-model="msg"></my-component>
const app = Vue.createApp({
    data() {
        return {
            msg: 'Hello Vue!!'
        }
    }
});
app.component('my-component', {
    props: ['modelValue'],
    template: `
    <input type="text" :modelValue="modelValue" @input="$emit('update:modelValue',$event.target.value)">
    `
})

自定义事件上使用v-model,属性及事件的名称改为

  • prop:value ⇒ modelValue
  • event:input ⇒ update:modelValue

跨层级传递

上下跨层

当父层元件要传递给最底部的元件时,可以透过provideinject机制。

  • provide : 定义要传递出去的资料(输出)
  • inject : 取得顶层元件资料 (取回)

Untitled

<input type="text" v-model="msg">
<list-component></list-component>
const app = Vue.createApp({
    data() {
        return {
            msg: 'Hello Vue!!'
        }
    },
    provide() {
        return {
            provideMsg: this.msg,
            provideMsg2: Vue.computed(() => this.msg)
        }
    }
});

若要子层inject取回的资料与上层连动,需透过Vue.computed()包装,包装後的物件要加.value才可以运作。

app.component('list-component', {
    template: `
    <ul>
        <li v-for="i in 3">
            {{i}}
            <list-item></list-item>
        </li>
    </ul>
    `,
    components: {
        'list-item': {
            inject: ['provideMsg', 'provideMsg2'],
            template: `
            <div>{{provideMsg}}</div>
            <div>{{provideMsg2.value}}</div>`
        }
    }
})

左右跨层

底层互相传递资料可以透过mitt处理。

  1. 先建立mitt()实体指定一个变数bus,并在vue实体上建立created,在bus身上注册reset事件
  2. <button-counter>元件身上新增created以对应reset事件
  3. <reset-button>元件身上放上reset方法

Untitled

Untitled

Vuex

Vue.js 3.x已不建议使用上述方式,改为Vuex管理

後面某一章节有这部分的内容,等到那天在来深入研究这一部分!今日的篇幅真够长的?

参考资料

JavaScript - 原始型别概述
https://ithelp.ithome.com.tw/articles/10192598
data为Object或Array时的浅拷贝特性
https://yuugou727.github.io/blog/2017/07/23/vue-data-is-object-or-array/
Vue.js中的methods,computed,watch。
https://codertw.com/程序语言/695853/#outline__3
Vue 3 到底有什么不同:v-model 升级了
https://segmentfault.com/a/1190000023462922


<<:  Day11-React 表单验证篇-不使用 hook 或第三方函式库

>>:  @Day25 | C# WixToolset + WPF 帅到不行的安装包 [既有的自订栏位介接]

JAVA - JAVA Log4j 专门用於 Java 语言的日志记录工具

JAVA - JAVA Log4j 专门用於 Java 语言的日志记录工具 参考资料 参考资料1:L...

第二十三天:在 TeamCity 上产生覆盖率报告

昨天介绍了测试覆盖率的概念,也在 IntelliJ IDEA 里将 ShoppingCart 类别的...

Day18 Lab 2 - Object storage metadata

Object的metadata让我们能快速定位Object在什麽地方、属性等等,可以理解为类似资料库...

从 IT 技术面细说 Search Console 的 27 组数字 KPI (4) 流量:图片、影片、新闻等多媒体流量

『导言』在 2019 年後,多媒体的搜寻流量在一些网站占比越来越高,现在可以说是经营网站的人都要去注...

建立你想要的文化(3)- 落地

将价值观转化为具体行为 有了明确的价值之後,下一步就是为每一个价值举出具体的行为。这是因为不管你陈述...