代码之家  ›  专栏  ›  技术社区  ›  Jérémy Halin

是否可以同步同一页面上多次显示的Vuejs组件?

  •  9
  • Jérémy Halin  · 技术社区  · 7 年前

    我有一个显示项目的网页。对于每个项目,都有一个按钮(vuejs组件),允许用户将此项目切换(添加/删除)到其集合中。

    以下是组件:

    <template lang="html">
            <button type="button" @click="toggle" name="button" class="btn" :class="{'btn-danger': dAdded, 'btn-primary': !dAdded}">{{ dText }}</button>
        </template>
    
    <script>
    export default {
        props: {
            added: Boolean,
            text: String,
            id: Number,
        },
        data() {
            return {
                dAdded: this.added,
                dText: this.text,
                dId: this.id
            }
        },
        watch: {
            added: function(newVal, oldVal) { // watch it
                this.dAdded = this.added
            },
            text: function(newVal, oldVal) { // watch it
                this.dText = this.text
            },
            id: function(newVal, oldVal) { // watch it
                this.dId = this.id
            }
        },
        methods: {
            toggle: function(event) {
                axios.post(route('frontend.user.profile.pop.toggle', {
                        pop_id: this.dId
                    }))
                    .then(response => {
                        this.dText = response.data.message
                        let success = response.data.success
                        this.dText = response.data.new_text
                        if (success) {
                            this.dAdded = success.attached.length
                            let cardPop = document.getElementById('card-pop-'+this.dId);
                            if(cardPop)
                                cardPop.classList.toggle('owned')
                        }
                    })
                    .catch(e => {
                        console.log(e)
                    })
            }
        }
    }
    </script>
    

    对于每个项目,用户还可以通过单击此链接打开一个模式:

    <a href="#" data-toggle="modal" data-target="#popModal" @click="id = {{$pop->id}}">
        <figure>
            <img class="card-img-top" src="{{ URL::asset($pop->img_path) }}" alt="Card image cap">
        </figure>
    </a>
    

    modal也是Vuejs组件:

    <template>
        <section id="pop" class="h-100">
            <div class="card">
                <div class="container-fluid">
                    <div class="row">
    
                        <div class="col-12 col-lg-1 flex-column others d-none d-xl-block">
                            <div class="row flex-column h-100">
    
                                <div v-for="other_pop in pop.other_pops" class="col">
                                    <a :href="route('frontend.pop.collection.detail', {collection: pop.collection.slug, pop: other_pop.slug})">
                                            <img :src="other_pop.img_path" :alt="'{{ other_pop.name }}'" class="img-fluid">
                                        </a>
                                </div>
    
                                <div class="col active order-3">
                                    <img :src="pop.img_path" :alt="pop.name" class="img-fluid">
                                </div>
    
                            </div>
                        </div>
    
                        <div class="col-12 col-lg-6 content text-center">
                            <div class="row">
                                <div class="col-12">
                                    <img :src="pop.img_path" :alt="pop.name" class="img-fluid">
                                </div>
    
                                <div class="col-6 text-right">
                                    <toggle-pop :id="pop.id" :added="pop.in_user_collection" :text="pop.in_user_collection ? 'Supprimer' : 'Ajouter'"></toggle-pop>
                                </div>
                                <div class="col-6 text-left">
                                    <!-- <btnaddpopwhishlist :pop_id="propid" :added="pop.in_user_whishlist" :text="pop.in_user_whishlist ? 'Supprimer' : 'Ajouter'"></btnaddpopwhishlist> -->
                                </div>
                            </div>
    
    
                        </div>
                        <div class="col-12 col-lg-5 infos">
                            <div class="header">
                                <h1 class="h-100">{{ pop.name }}</h1>
                            </div>
                            <div class="card yellow">
                                <div class="card p-0">
                                    <div class="container-fluid">
                                        <div class="row">
                                            <div class="col-3 py-2">
    
                                            </div>
                                            <div class="col-6 py-2 bg-lightgray">
                                                <h4>Collection:</h4>
                                                <h3>{{ pop.collection ? pop.collection.name : '' }}</h3>
                                            </div>
                                            <div class="col-3 py-2 bg-lightgray text-center">
                                                <a :href="route('frontend.index') + 'collections/' + pop.collection.slug" class="btn-round right white"></a>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </template>
    
    <script>
    export default {
        props: {
            id: Number
        },
        data() {
            return {
                pop: {
                    collection: {
    
                    }
                }
            }
        },
        ready: function() {
            if (this.propid != -1)
                this.fetchData()
        },
        watch: {
            id: function(newVal, oldVal) { // watch it
                // console.log('Prop changed: ', newVal, ' | was: ', oldVal)
                this.fetchData()
            }
        },
        computed: {
            imgSrc: function() {
                if (this.pop.img_path)
                    return 'storage/images/pops/' + this.pop.img_path
                else
                    return ''
            }
        },
        methods: {
            fetchData() {
                axios.get(route('frontend.api.v1.pops.show', this.id))
                    .then(response => {
                        // JSON responses are automatically parsed.
                        // console.log(response.data.data.collection)
                        this.pop = response.data.data
                    })
                    .catch(e => {
                        this.errors.push(e)
                    })
                // console.log('fetchData')
            }
        }
    }
    </script>
    

    这是我的应用程序。js脚本:

    window.Vue = require('vue');
    
    Vue.component('pop-modal', require('./components/PopModal.vue'));
    Vue.component('toggle-pop', require('./components/TogglePop.vue'));
    
    const app = new Vue({
        el: '#app',
        props: {
            id: Number
        }
    });
    

    我想同步名为的组件的状态 toggle-pop ,我如何才能做到这一点?一个是通过刀片模板(laravel)渲染的,另一个是通过 pop-modal 组成部分但它们是一样的,陈列在不同的地方。

    谢谢

    2 回复  |  直到 7 年前
        1
  •  4
  •   Marco Pantaleoni    7 年前

    可以将状态对象作为属性传递给 toggle-pop 组件。他们可以使用此属性存储/修改其状态。通过这种方式,可以让多组组件共享状态。

    您的组件可能会成为:

    <template lang="html">
      <button type="button" @click="toggle" name="button" class="btn" :class="{'btn-danger': sstate.added, 'btn-primary': !sstate.added}">{{ sstate.text }}</button>
    </template>
    
    <script>
    export default {
      props: {
        sstate: {
          type: Object,
          default: function() {
            return { added: false, text: "", id: -1 };
          }
        }
      },
      data() {
        return {};
      },
      methods: {
        toggle: function(event) {
          axios.post(route('frontend.user.profile.pop.toggle', {
            pop_id: this.sstate.id
          }))
            .then(response => {
                this.sstate.text = response.data.message
                let success = response.data.success
                this.sstate.text = response.data.new_text
                if (success) {
                    this.sstate.ddded = success.attached.length
                    let cardPop = document.getElementById('card-pop-'+this.sstate.id);
                    if(cardPop)
                        cardPop.classList.toggle('owned')
                }
            })
            .catch(e => {
              console.log(e)
            })
      }
    };
    </script>
    

    现场演示

    https://codesandbox.io/s/vq8r33o1w7

        2
  •  2
  •   Jacob Goh    7 年前

    如果你是 百分之百确定 toggle-pop 组件应始终具有相同的状态 ,您可以选择不定义 data 作为一种功能。只需将其声明为对象即可。

      data: {
        dAdded: this.added,
        dText: this.text,
        dId: this.id
      }
    

    在里面 https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function ,它提到

    组件数据选项必须是一个函数,以便每个实例 可以维护返回数据对象的独立副本

    如果Vue没有此规则,单击一个按钮将影响 所有其他实例的数据

    因为您想同步所有 切换弹出窗口 组件实例,您不必遵循 data option must be a function 规则