前言
今天给我的网站的博客相关页面新增了侧边菜单,用来显示年份索引和 TOC(Table of Contents, 文章小标题目录)。
博客列表的年份索引在桌面版时显示在右侧,手机版时隐藏,文章详情页的 TOC 在桌面和手机都隐藏,侧边菜单可使用固定在页面右下角的列表按钮进行开关。
就这么个功能做了一整天。不过做的时候遇到一些问题,又学到了一些关于 Vue.js
开发的小知识,主要涉及到的是 Vue 父子组件的通信,包括传值和触发调用方法。
(并没有,其实只是没看文档就瞎写的后遗症而已)
父组件给子组件内嵌Vue表达式
要在组件里内嵌 Vue 表达式或者 HTML 的话,需要在原组件中把内嵌的位置写上 <slot></slot>
,这就是在应用组件时插入表达式或 HTML 的插槽。
要注意的是,插槽不可以是根元素标签,必须写在内嵌位置的里面。
子组件:
<div class="side-nav">
<slot></slot>
</div>
父组件:
<div>
<h2>Year list</h2>
<SideNav class="side-unit">
<ul class="year-list">
<li v-for="(year,i) in years" :key="i">
{{year}}
</li>
</ul>
</SideNav>
</div>
最终渲染的结果如下:
<div>
<h2>Year list</h2>
<div class="side-nav side-unit">
<ul class="year-list">
<li>
2021(18)
</li>
<li>
2020(10)
</li>
</ul>
</div>
</div>
父组件给子组件绑定点击事件
本来如果要在 HTML 标签上绑定点击事件的时候只需要 v-on:click="xxx"
或者 @click="xxx"
就可以了,但是如果是组件的话就需要加个 native
完整的是这样:
<ListButton @click.native="toggleSideNav"></ListButton>
父组件给子组件传递布尔值
本来如果要传递固定内容的字符串给组件的 props
时是不需要用 v-bind:
或者 :
符号的,但是如果要传递的是布尔值,就需要了。
<ListButton :isDesk="true"></ListButton>
父子组件同时控制一个值
如果一个 prop
是依赖父组件传值,但是又希望在子组件内部可以更改的,那就不要用 prop
传值,而是改成子组件内的 data
,把更改 data
的方法在 methods
里面写好,这样子组件内部可以调用,然后再在父组件内触发调用子组件的方法。
子组件:
<div class="side-nav" :class="{'show': isShow}">
<slot></slot>
<div @click="toggle">
<i class="fa fa-window-close-o"></i>
</div>
</div>
export default {
data() {
return {
isShow: false
}
},
methods: {
toggle() {
this.isShow = this.isShow?false:true;
}
}
}
然后到父组件,这里的 ref
是触发调用的关键。
<SideNav class="side-unit" ref="mySideNav"></SideNav>
<ListButton @click.native="toggleSideNav"></ListButton>
methods: {
toggleSideNav: function() {
this.$refs.mySideNav.toggle();
}
}
总结及其他
关于 Vue 开发中的兄弟组件通信的问题,另有一篇写 Nuxt 面包屑导航的文章 如何制作中英双语的面包屑导航。
另外,以上四个问题的答案出自这四个页面
Passing html into Vue component
Vue v-on:click does not work on component
Passing boolean Vue prop value in HTML
Stackoverflow 和 cnblogs 真是人民的大救星!