Switch Vuetify navigation drawer to mini and then

2019-08-26 03:21发布

问题:

I have a project in Vue.js and I am using Vuetify. I have a toolbar and navigation drawer. What I would like is when on desktop the drawer is open. If the user clicks the side-icon the drawer switches to mini.

If on md the drawer switches to mini. if the user clicks the side-icon the mini switches back to drawer

If on sm or lower the navigation drawer switches to temporary

I have most of the pieces but I am getting an error when I click the side-icon. Computed property 'mini' was assigned to but it has no setter.

Here is my code:

<v-toolbar 
    :clipped-left="$vuetify.breakpoint.mdAndUp"
    :app="$vuetify.breakpoint.mdAndUp"
    :fixed="$vuetify.breakpoint.mdAndUp"
    flat 
    fixed
    :scroll-toolbar-off-screen="$vuetify.breakpoint.smAndDown"
    :scroll-threshold="50">

    <v-toolbar-side-icon @click.stop="mini = !mini">
    </v-toolbar-side-icon>

    <v-toolbar-title class="text-uppercase">
        <span class="font-weight-light">LOGO</span>
    </v-toolbar-title>
    <v-spacer></v-spacer>
    <v-toolbar-items class="">
        <v-btn icon v-for="item in menu" :key="item.icon">
            <v-icon>{{item.icon}}</v-icon>
        </v-btn>
    </v-toolbar-items>
</v-toolbar>

<v-navigation-drawer 
    clipped 
    :mini-variant="mini"
    v-model="drawer"
    :permanent="$vuetify.breakpoint.mdOnly"
    :temporary="$vuetify.breakpoint.smAndDown"
    app
    hide-overlay>

    <v-list dense>
        <v-list-tile
            v-for="(item, index) in items"
            :key="index"
        >
            <v-list-tile-action>
                <v-icon>{{ item.icon }}</v-icon>
            </v-list-tile-action>

            <v-list-tile-content>
                <v-list-tile-title>{{ item.title }}</v-list-tile-title>
            </v-list-tile-content>
        </v-list-tile>
    </v-list>
</v-navigation-drawer>

I have created a codepen with what I have so far:

https://codepen.io/jsd219/pen/gJJMPQ

回答1:

You're trying to assign a computed property to itself:

@click.stop="mini != mini"

You really don't want to do that. To find out why, you want to read on JS setters and getters.

If you want mini to be the computed which determines if your <navigation-drawer> is minified or not, use two separate placeholders for your info:

  • one for whether the menu is forcefully opened (call it menuOpen), initially defined in data(), as false and then overwritten by your @click.stop="menuOpen != menuOpen"
  • and one coming from $vuetify.breakpoint.mdAndUp. Call it mdAndUp.

So your mini becomes:

  mini() {
    return !(this.mdAndUp|| this.menuOpen);
  }

See it here.



回答2:

The problem is that you are trying to modify the computed property mini.

To mutate a computed property, you would need to provide a computed setter:

computed: {
    mini: {
        get() {
           // get logic
        },
        set(value) {
           // set logic
        }
    }
}

In your case, your computed property mini returns true or false if based on $vuetify.breakpoint.mdAndDown. You would need to include a new variable, something like overwriteBreakpoint and use that in your setter.

data() => ({
    overwriteBreakpoint: true
}),
computed: {
    mini: {
        get() {
           return this.$vuetify.breakpoint.mdAndDown || this.overwriteBreakpoint;            
        },
        set(value) {
           this.overwriteBreakpoint = value;
        }
    }
}

Here's an example: https://codepen.io/dormenog/pen/MddbMY?editors=1011

Update:

To make this work on multiple screen sizes you'll need to come up with defined rules on when each prop of your nav bar should be true or false. This will become very messy, very quickly, and the benefit of the keeping track of the state is not really valuable because the screens will not change size in real time on the user's device.

I would advice separating the contents of your navbar into a component and wrap it with multiple <v-navigation-drawer /> that will only be rendered by vue if the screen size is correct. This can be achieved using v-if and v-else.