Oh, my gosh...
Vue.jsã®Propsã£ã¦è¦ªã³ã³ãã¼ãã³ãããåã³ã³ãã¼ãã³ãã«ãã¼ã¿ã渡ããã®ã ããï¼
Vue.jsã®Propsã¨è¨ãã°ã親ã³ã³ãã¼ãã³ãããåã³ã³ãã¼ãã³ãã«ãã¼ã¿ã渡ããã®ã ããï¼
Usually, when we need to pass data from the parent to a child component, we use props. However, imagine the case where we have a large component tree, and a deeply nested component needs something from a distant ancestor component. With only props, we would have to pass the same prop across the entire parent chain:
https://vuejs.org/guide/components/provide-inject.html#prop-drilling
⧠ä¸è¬çã«ãæã ã¯ãPropsã使ãå¿ è¦ãããã£ã¦è¨ã£ã¦ã¾ããã
Vue.jsã®Propsã¯èªåèªèº«ã«æ¸¡ããããã
ãããªå®èª¬ãè¦ãã³ã¼ãããã£ãã¨ãã
<template>
{{my_array}}
<my-component :my_counter="compA()">
</template>
<script>
module.exports = {
props: ['my_counter'],
name: 'my-component',
computed: {
compA() {
const my_counter = this.my_counter ? this.my_counter : [];
let my_array = [name: "static name", counter: my_counter];
return my_array;
}
}
}
</script>
https://stackoverflow.com/questions/66277762/vue-js-recursive-components-data-including-props
⧠ãï½ããä½åº¦è¦ã¦ããèªã³ã³ãã¼ãã³ãå ã§Propsãå®ç¾©ãã¦ãå¼ã³åºãã¦ãã£ãããããã«è¦ãã...
ã¨è¨ãã®ãã
⧠ä¸è¨ã®ã³ã¼ããè¦ã¦ãããåããèªã³ã³ãã¼ãã³ãå ã§Propsãå¼ãã§ãã£ãããæ°é ã ã£ããã®ã§ã
â vue-admin/vue-typescript-admin-template/src/layout/components/Sidebar/SidebarItem.vue
<template> <div v-if="!item.meta || !item.meta.hidden" :class="[isCollapse ? 'simple-mode' : 'full-mode', {'first-level': isFirstLevel}]" > <template v-if="!alwaysShowRootMenu && theOnlyOneChild && !theOnlyOneChild.children"> <sidebar-item-link v-if="theOnlyOneChild.meta" :to="resolvePath(theOnlyOneChild.path)" > <el-menu-item :index="resolvePath(theOnlyOneChild.path)" :class="{'submenu-title-noDropdown': isFirstLevel}" > <svg-icon v-if="theOnlyOneChild.meta.icon" :name="theOnlyOneChild.meta.icon" /> <span v-if="theOnlyOneChild.meta.title" slot="title" >{{ $t('route.' + theOnlyOneChild.meta.title) }}</span> </el-menu-item> </sidebar-item-link> </template> <el-submenu v-else :index="resolvePath(item.path)" popper-append-to-body > <template slot="title"> <svg-icon v-if="item.meta && item.meta.icon" :name="item.meta.icon" /> <span v-if="item.meta && item.meta.title" slot="title" >{{ $t('route.' + item.meta.title) }}</span> </template> <template v-if="item.children"> <sidebar-item v-for="child in item.children" :key="child.path" :item="child" :is-collapse="isCollapse" :is-first-level="false" :base-path="resolvePath(child.path)" class="nest-menu" /> </template> </el-submenu> </div> </template> <script lang="ts"> import path from 'path' import { Component, Prop, Vue } from 'vue-property-decorator' import { RouteConfig } from 'vue-router' import { isExternal } from '@/utils/validate' import SidebarItemLink from './SidebarItemLink.vue' @Component({ // Set 'name' here to prevent uglifyjs from causing recursive component not work // See https://medium.com/haiiro-io/element-component-name-with-vue-class-component-f3b435656561 for detail name: 'SidebarItem', components: { SidebarItemLink } }) export default class extends Vue { @Prop({ required: true }) private item!: RouteConfig @Prop({ default: false }) private isCollapse!: boolean @Prop({ default: true }) private isFirstLevel!: boolean @Prop({ default: '' }) private basePath!: string get alwaysShowRootMenu() { if (this.item.meta && this.item.meta.alwaysShow) { return true } return false } get showingChildNumber() { if (this.item.children) { const showingChildren = this.item.children.filter((item) => { if (item.meta && item.meta.hidden) { return false } else { return true } }) return showingChildren.length } return 0 } get theOnlyOneChild() { if (this.showingChildNumber > 1) { return null } if (this.item.children) { for (const child of this.item.children) { if (!child.meta || !child.meta.hidden) { return child } } } // If there is no children, return itself with path removed, // because this.basePath already conatins item's path information return { ...this.item, path: '' } } private resolvePath(routePath: string) { if (isExternal(routePath)) { return routePath } if (isExternal(this.basePath)) { return this.basePath } return path.resolve(this.basePath, routePath) } } </script> <style lang="scss"> .el-submenu.is-active > .el-submenu__title { color: $subMenuActiveText !important; } .full-mode { .nest-menu .el-submenu>.el-submenu__title, .el-submenu .el-menu-item { min-width: $sideBarWidth !important; background-color: $subMenuBg !important; &:hover { background-color: $subMenuHover !important; } } } .simple-mode { &.first-level { .submenu-title-noDropdown { padding: 0 !important; position: relative; .el-tooltip { padding: 0 !important; } } .el-submenu { overflow: hidden; &>.el-submenu__title { padding: 0px !important; .el-submenu__icon-arrow { display: none; } &>span { visibility: hidden; } } } } } </style> <style lang="scss" scoped> .svg-icon { margin-right: 16px; } .simple-mode { .svg-icon { margin-left: 20px; } } </style>
â vue-admin/vue-typescript-admin-template/src/layout/components/Sidebar/index.vue
<template> <div :class="{'has-logo': showLogo}"> <sidebar-logo v-if="showLogo" :collapse="isCollapse" /> <el-scrollbar wrap-class="scrollbar-wrapper"> <el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" :active-text-color="menuActiveTextColor" :unique-opened="false" :collapse-transition="false" mode="vertical" > <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" :is-collapse="isCollapse" /> </el-menu> </el-scrollbar> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator' import { AppModule } from '@/store/modules/app' import { PermissionModule } from '@/store/modules/permission' import { SettingsModule } from '@/store/modules/settings' import SidebarItem from './SidebarItem.vue' import SidebarLogo from './SidebarLogo.vue' import variables from '@/styles/_variables.scss' @Component({ name: 'SideBar', components: { SidebarItem, SidebarLogo } }) export default class extends Vue { get sidebar() { return AppModule.sidebar } get routes() { return PermissionModule.routes } get showLogo() { return SettingsModule.showSidebarLogo } get menuActiveTextColor() { if (SettingsModule.sidebarTextTheme) { return SettingsModule.theme } else { return variables.menuActiveText } } get variables() { return variables } get activeMenu() { const route = this.$route const { meta, path } = route // if set path, the sidebar will highlight the path you set if (meta.activeMenu) { return meta.activeMenu } return path } get isCollapse() { return !this.sidebar.opened } } </script> <style lang="scss"> .sidebar-container { // reset element-ui css .horizontal-collapse-transition { transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; } .scrollbar-wrapper { overflow-x: hidden !important; } .el-scrollbar__view { height: 100% } .el-scrollbar__bar { &.is-vertical { right: 0px; } &.is-horizontal { display: none; } } } </style> <style lang="scss" scoped> .el-scrollbar { height: 100% } .has-logo { .el-scrollbar { height: calc(100% - 50px); } } .el-menu { border: none; height: 100%; width: 100% !important; } </style>
⧠親ã³ã³ãã¼ãã³ãã®æ¹ã§ãå¼ãã§ãã£ã½ããã©ãåã³ã³ãã¼ãã³ãèªèº«ã§ãPropsãå¼ãã§ãã£ã½ãã®ãã...
ãï½ããVue.jsãç¸å¤ãããã«ãªã¹ãªæ°ããã...
ããã¥ã¡ã³ãè¦ããã©ãã
⧠親ã³ã³ãã¼ãã³ãâåã³ã³ãã¼ãã³ãã以å¤ã®ä½¿ãæ¹ãããã£ã¦ãã¨ãªãããªï¼
æ¯åº¦ã¢ã¤ã¢ã¤æãå端ãªã...
ä»åã¯ãã®ã¸ãã§ã
Â
Â