【问题标题】:How to solve an issue with vue-transitions being triggered or not through methods如何解决通过方法触发或不触发 vue-transitions 的问题
【发布时间】:2020-04-15 05:56:51
【问题描述】:

我正在vue-cli 上进行一个研究项目,尽管这是一个简单的项目,但我正在尝试应用我一直在学习的一些东西。

我有一个带有两个routes 的标题:

  • 投资组合
  • 股票

一旦进入这两个routes中的任何一个,我已经设置了一个简单的fade动画。

这里有两个问题,我认为两者都是相关的。我会在按照下面列出的code 块发布后进入它。

我将在下面发布我的代码:

Header.vue(这是我的头文件)

<template>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <router-link to="/" class="navbar-brand"><a>Stock Trade</a></router-link>
        <div class="d-inline" @click="toPortfolio">
            <ul class="navbar-nav mr-auto">
                <router-link :to="{ name: 'portfolio'}"
                             tag="li" class="nav-item nav-link"><a
                             class="text-decoration-none">Portfolio</a></router-link>
            </ul>
        </div>
        <div class="collapse navbar-collapse" @click="toStocks">
            <ul class="navbar-nav mr-auto">
                <router-link :to="{name: 'stocks'}"
                             tag="li" class="nav-item nav-link">
                    <a class="text-decoration-none">Stocks</a>
                </router-link>
            </ul>
        </div>
        <div class="collapse navbar-collapse end-day">
            <div class="navbar-nav ml-auto">
                <li class="nav-item nav-link">End Day</li>
            </div>
        </div>
        <div class="d-inline" @click="isDropping = !isDropping">
            <ul class="navbar-nav ml-auto">
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle"
                       href="#"
                       role="button"
                       data-toggle="dropdown"
                       aria-haspopup="true"
                       aria-expanded="false">
                        Save & Load <span class="dropdown-toggle-no-caret"></span>
                    </a>
                    <!-- I must understand why it does not work below-->
                    <div class="dropdown-menu"
                         :class="{show: isDropping}"
                         aria-labelledby="navbarDropdown">
                        <a class="dropdown-item " href="#">Save Data</a>
                        <a class="dropdown-item" href="#">Load Data</a>
                    </div>
                </li>
            </ul>
        </div>
        <div>
            <!-- Got to add a Getter here instead so "DRY" does not happen with the "EUR" assignment-->
            <strong class="navbar-text" style="color: dimgray">Funds: {{$store.state.funds}}</strong>
        </div>
    </nav>
</template>
<script>
    import {mapActions} from 'vuex'
    import * as types from '/Users/Dev/WebstormProjects/the-trader-app/src/store/types.js'
    export default {
        data() {
            return {
                isDropping: false
            }
        },
        methods: {
            ...mapActions({
                toPortfolio: types.COMMIT_TO_PORTFOLIO,
                toStocks: types.COMMIT_TO_STOCKS
            })
        }
    }

</script>
<style scoped>
    a {
        color: dimgray;
    }

    a:hover{
        color: black !important;
    }

    .end-day {
        cursor: pointer;
    }
</style>

Stocks.vue(这是显示股票的地方)

<template>
    <div class="d-flex flex-wrap justify-content-sm-around">
        <transition name="fade">
            <div class="wrapper" v-if="showStocks">
                <div class="stock-title">
                    <h4 class="box-headers">BMW</h4>
                    <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
                </div>
                <div class="stock-content">
                    <input type="text" class="mr-auto" placeholder="How many shares?">
                    <button>Buy</button>
                </div>
            </div>
        </transition>
        <transition name="fade">
            <div class="wrapper" v-if="showStocks">
                <div class="stock-title">
                    <h4 class="box-headers">Apple</h4>
                    <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
                </div>
                <div class="stock-content">
                    <input type="text" class="mr-auto" placeholder="How many shares?">
                    <button>Buy</button>
                </div>
            </div>
        </transition>
        <transition name="fade">
            <div class="wrapper" v-if="showStocks">
                <div class="stock-title">
                    <h4 class="box-headers">Facebook</h4>
                    <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
                </div>
                <div class="stock-content">
                    <input type="text" class="mr-auto" placeholder="How many shares?">
                    <button>Buy</button>
                </div>
            </div>
        </transition>
        <transition name="fade">
            <div class="wrapper" v-if="showStocks">
                <div class="stock-title">
                    <h4 class="box-headers">Google</h4>
                    <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
                </div>
                <div class="stock-content">
                    <input type="text" class="mr-auto" placeholder="How many shares?">
                    <button>Buy</button>
                </div>
            </div>
        </transition>
    </div>
</template>
<script>
    import {mapGetters} from 'vuex';
    import * as types from '/Users/Dev/WebstormProjects/the-trader-app/src/store/types.js';

    export default {
        computed: {
            ...mapGetters({
                showStocks: types.GET_STOCKS
            })
        }
    }
</script>
<style scoped>

    .wrapper {
        border: solid lightgray 1px;
        width: 500px;
        margin-top: 20px;
        border-radius: 5px;
        box-shadow: 3px 3px 5px 6px #ccc;
    }

    .stock-title {
        background-color: lightskyblue;
        color: royalblue;
        display: flex;
        flex-wrap: wrap;
        padding: 7px 0 0 20px;
    }

    .box-headers {
        display: inline-block;
        margin: 0;
        padding: 10px -1px 10px 10px;
    }

    p {
        align-self: flex-end;
    }

    .stock-content {
        display: flex;
    }

    input {
        margin: 10px;
        padding: 10px;
    }

    button {
        background-color: royalblue;
        color: white;
        padding: 0 20px;
        border-radius: 5px;
        justify-self: center;
        margin: 10px;
    }

    ::placeholder {
        font-size: 15px;
    }

    .fade-enter {
        opacity: 0;
    }

    .fade-enter-active {
        transition: opacity 2s;
    }

    .fade-leave-active {
        transition: opacity 2s;
        opacity: 0;
    }


</style>

Portfolio.vue

<template>
    <div class="d-flex flex-wrap justify-content-sm-around">
        <transition name="fade">
        <div class="wrapper" v-if="showPortfolio">
            <div class="stock-title">
                <h4 class="box-headers">BMW</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="showPortfolio">
            <div class="stock-title">
                <h4 class="box-headers">Apple</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="showPortfolio">
            <div class="stock-title">
                <h4 class="box-headers">Facebook</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="showPortfolio">
            <div class="stock-title">
                <h4 class="box-headers">Google</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
    </div>
</template>
<script>
    import {mapGetters} from 'vuex';
    import * as types from '/Users/Dev/WebstormProjects/the-trader-app/src/store/types.js';

    export default {
        computed: {
            ...mapGetters({
                showPortfolio: types.GET_PORTFOLIO
            })
        }
    }
</script>

<style scoped>

    .wrapper {
        border: solid lightgray 1px;
        width: 500px;
        margin-top: 20px;
        border-radius: 5px;
        box-shadow: 3px 3px 5px 6px #ccc
    }

    .stock-title {
        background-color: #ffbf00;
        color: indianred;
        display: flex;
        flex-wrap: wrap;
        padding: 7px 0 0 20px;
    }

    .box-headers {
        display: inline-block;
        vertical-align: baseline;
        margin: 0;
        padding: 10px -1px 10px 10px;
    }

    .stock-content {
        display: flex;
    }

    p {
        align-self: flex-end;
    }

    input {
        margin: 10px;
        padding: 10px;
    }

    button {
        background-color: indianred;
        color: white;
        padding: 0 20px;
        border-radius: 5px;
        justify-self: center;
        margin: 10px;
    }

    ::placeholder {
        font-size: 15px;
    }

    .fade-enter {
        opacity: 0;
    }

    .fade-enter-active {
        transition: opacity 2s;
    }

    .fade-leave-active {
        transition: opacity 2s;
        opacity: 0;
    }

ma​​in.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router";
import 'bootstrap/dist/css/bootstrap.css'
import BootstrapVue from 'bootstrap-vue'
import {store} from "./store/store";
import {routes} from "./routes";

Vue.use(BootstrapVue);
Vue.use(VueRouter);

export const router = new VueRouter({
  routes,
  mode: 'history',
  scrollBehavior(to, from, savedPosition) {
    if(savedPosition) {
      return savedPosition
    }
    if (to.hash) {
      return {selector: to.hash}
    }
    return {x: 0, y: 0};
  }
});

new Vue({
  el: '#app',
  store,
router,
  render: h => h(App)
});

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import altAnims from "@/store/modules/altAnims";

Vue.use(Vuex);

export const store = new Vuex.Store({
   state: {
      sharesValue: {
         BMW: 1,
         Apple: 0,
         FaceBook: 0,
         Google: 0
      },
      user:{
         funds: 1000,
         shares: {
            BMW: 0,
            Apple: 0,
            FaceBook: 0,
            Google: 0
         }
      }
   },
   modules: {
      altAnims
   }
});

types.js

// Getters
export const GET_PORTFOLIO = 'portfolio/shared';
export const GET_STOCKS = 'stocks/shared';
//Mutations
export const MUTATE_PORTFOLIO = 'shared/SET_PORTFOLIO';
export const MUTATE_STOCKS = 'shared/SET_STOCKS';
//Actions
export const COMMIT_TO_PORTFOLIO = 'shared/ALTERNATE_PORTFOLIO';
export const COMMIT_TO_STOCKS = 'shared/ALTERNATE_STOCKS';

altAnims.js(这是我玩这个动画的地方)

import * as types from '../types';

const state = {
    showStock: false,
    showPortfolio: false
};

const getters = {
    [types.GET_PORTFOLIO]: state => {
        return state.showPortfolio
    },
    [types.GET_STOCKS]: state => {
        return state.showStock
    }
};

const mutations = {
    [types.MUTATE_PORTFOLIO]: state => {
        state.showPortfolio = true;
        state.showStock = false
    },
    [types.MUTATE_STOCKS]: state => {
        state.showStock = true;
        state.showPortfolio = false
    }
};

const actions = {
[types.COMMIT_TO_PORTFOLIO]: ({commit}) => {
    commit(types.MUTATE_PORTFOLIO);
},
    [types.COMMIT_TO_STOCKS]: ({commit}) => {
    commit(types.MUTATE_STOCKS);
    }
};

export default {
    state,
    getters,
    mutations,
    actions
}

第一期

我尝试做的第一件事是创建简单的fade 动画,你们可以在Stocks.vuePortfolio.vue 文件上看到,这应该由@click 上的@click 事件触发。

嗯,第一个问题是,由于某种原因,当我重新加载页面并第一次触发 @click event 进入 Profile.vueStocks.vue 中的任何一个时animation 不会发生。但是在彼此之间切换后它开始工作。

我不明白为什么它在第一次点击时不起作用,因为您可以在altAnims.js 上看到这两个项目的state 最初设置为false

const state = {
    showStock: false,
    showPortfolio: false
};

然后一旦提交mutatingactionstate,正如您在altAnims.js 的进展中看到的那样,反转他们的Boolean 语句,在第一次点击时v-if 应该阅读@987654355 @ 与 falsestatetrue,您可以在 Header.vue 看到 @click 事件的作用

第二期

虽然我一开始没有解决这个问题,但我还是试着继续前进。

这就是我尝试做的@@Portfolio.vue

<template>
    <div class="d-flex flex-wrap justify-content-sm-around">
        <transition name="fade">
        <div class="wrapper" v-if="revealBMW">
            <div class="stock-title">
                <h4 class="box-headers">BMW</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="revealApple">
            <div class="stock-title">
                <h4 class="box-headers">Apple</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="revealFaceBook">
            <div class="stock-title">
                <h4 class="box-headers">Facebook</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
        <transition name="fade">
        <div class="wrapper" v-if="revealGoogle">
            <div class="stock-title">
                <h4 class="box-headers">Google</h4>
                <p class="box-headers" style="font-size: 13px">(Price: 20 EUR)</p>
            </div>
            <div class="stock-content">
                <input type="text" class="mr-auto" placeholder="How many shares?">
                <button>Sell</button>
            </div>
        </div>
        </transition>
    </div>
</template>
<script>
    import {mapGetters} from 'vuex';
    import * as types from '/Users/Dev/WebstormProjects/the-trader-app/src/store/types.js';

    export default {
        computed: {
            ...mapGetters({
                showPortfolio: types.GET_PORTFOLIO
            })
        },
        methods: {
            revealBMW(){
                if(this.$store.state.sharesValue.BMW > 0) {
                    return this.showPortfolio
                }
            },
            revealApple(){
                if(this.$store.state.sharesValue.Apple > 0) {
                    return this.showPortfolio                }
            },
            revealFaceBook(){
                if(this.$store.state.sharesValue.FaceBook > 0) {
                    return this.showPortfolio                }
            },
            revealGoogle(){
                if(this.$store.state.sharesValue.Google > 0) {
                    return this.showPortfolio                }
            }
        }
    }
</script>

<style scoped>

    .wrapper {
        border: solid lightgray 1px;
        width: 500px;
        margin-top: 20px;
        border-radius: 5px;
        box-shadow: 3px 3px 5px 6px #ccc
    }

    .stock-title {
        background-color: #ffbf00;
        color: indianred;
        display: flex;
        flex-wrap: wrap;
        padding: 7px 0 0 20px;
    }

    .box-headers {
        display: inline-block;
        vertical-align: baseline;
        margin: 0;
        padding: 10px -1px 10px 10px;
    }

    .stock-content {
        display: flex;
    }

    p {
        align-self: flex-end;
    }

    input {
        margin: 10px;
        padding: 10px;
    }

    button {
        background-color: indianred;
        color: white;
        padding: 0 20px;
        border-radius: 5px;
        justify-self: center;
        margin: 10px;
    }

    ::placeholder {
        font-size: 15px;
    }

    .fade-enter {
        opacity: 0;
    }

    .fade-enter-active {
        transition: opacity 2s;
    }

    .fade-leave-active {
        transition: opacity 2s;
        opacity: 0;
    }
</style>

我添加了一些methods,所以每次我进入这条路线时,我只会在altAnims.js 的状态下显示共享数量超过0 的容器。为了测试这一点,我对BMW: 1 进行了硬编码,最终结果是animation 停止工作,BMW 股票container 也没有回复我的methods

我不确定这是否是一个好习惯,也许将这些方法放在 computed 中,或者我缺少的完全不同的东西。

抱歉这么长的问题,充满了代码块。我试图尽可能详细。

我想就这两个问题

获得帮助

P.S - 我刚刚想到的一个想法是,对于在这种情况下要加载的每个 container,这是否可以使用 templates。没试过,有可能吗?

提前干杯和感谢!

【问题讨论】:

  • 伙计,这代码太多了。你应该create a Minimal, Reproducible Example你的问题......最好是在像 Codesandbox 这样的网站上,这样人们就可以运行它并进行实验。一些笔记......为什么你要以如此复杂的方式进行转换?您正在使用 Vue 路由器,但我仍然没有在任何地方看到 &lt;router-view&gt;。看看here 如何在没有v-if、Vuex 和所有这些东西的情况下在路由之间进行转换。

标签: vue.js css-animations vuex vue-cli vue-transitions


【解决方案1】:

要写的东西太多了,Codereview 会是更好的地方,但是....

Here你可以找到我对这个问题的看法。要寻找的东西:

  1. 使用 &lt;route-view&gt; 而不使用 vuex 和其他复杂内容的过渡 - 使用 appear 进行调整,使其在初始渲染和 mode="out-in" 时进行过渡(只需尝试将其移除以查看效果)
  2. 更好的存储状态 - 不要使用公司名称作为对象键,并非每个公司名称都是有效的 JS 标识符
  3. 重写了 PortfolioStocks 组件以使用 v-for 从存储中呈现数组数据

使用 Vue 路由器进行转换

<transition name="fade" mode="out-in" appear>
  <router-view :key="$route.fullPath"/>
</transition>

【讨论】:

  • 非常感谢所有这些帮助我的工作!它看起来更整洁。现在我想弄清楚如何限制在 v-for 中传递的内容,试图在 v-for stackoverflow.com/questions/59472978/… 中传递 method 。我不知道 Codereview!先生,我将确保永远不再重复我在这里所做的这种混乱!非常非常感谢!
猜你喜欢
  • 2019-04-24
  • 2011-05-28
  • 1970-01-01
  • 2022-10-26
  • 1970-01-01
  • 2018-04-30
  • 2014-01-01
  • 1970-01-01
  • 2020-07-08
相关资源
最近更新 更多