javascript - 在组件内部单击按钮,调用父方法。如何?

标签 javascript vue.js vue-component

下面是一个包含 3 个 notify() 方法的功能性 App。

在组件索引中找到第一个 notify() 方法。

第二个notify()方法是在组件登录中找到的。

第三个 notify() 方法在父 App 实例中找到。

问题:

如何通过单击登录按钮调用在父 App 实例中找到的第三个 notify()

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Simple Vue.js Router Example</title>

    <!-- VUE JS v2.6.1 -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <!-- VUE ROUTER JS v3.1.3 -->
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <!-- BOOTSTRAP CSS v4.3.1 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <!-- GOOGLE FONT CSS - Roboto Mono -->
    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono:100,300,400,500,700&display=swap" rel="stylesheet">
    <!-- GOOGLE FONT CSS - Material Icons -->
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <!-- CSS -->

    <style type="text/css">

      body {
        font-family: 'Roboto Mono', monospace;
        font-weight: 400;
        font-size: 1rem;
        background-color: #d7ccc8;
      }

      .active {
        color: MediumSeaGreen;
      }

      .exactActive {
        color: #e57373;
      }

    </style>

  </head>

  <body>

    <!--  
      HTML

    -->
    <!-- VUE APP - PARENT CONTAINER -->
    <div id="app" class="container">

      <!-- HEADER CONTAINER -->
      <header>

        <!--  
          LINKS

        -->
        <!-- ROUTER LINK(S) -->
        <ul>
          <li>
            <router-link tag="a" to="/" exact>/index</router-link>
          </li>
          <li>
            <router-link tag="a" to="/sign-in">/sign-in</router-link>
          </li>

        </ul>

        <!--  
          VIEWS

        -->
        <!-- ANY OF THESE CAN/DO OR DO NOT RENDER -->
        <!-- DEPENDS ON ROUTER-LINK SELECTED -->

        <router-view name="RTV_index"></router-view>
        <router-view name="RTV_sign_in"></router-view>

      </header>

    </div>

    <!--  
      JAVASCRIPT

    -->

    <!-- JAVA SCRIPT -->
    <script type="text/javascript">

      // DISABLE
      Vue.config.productionTip = false;
      // DISABLE
      Vue.config.devtools = false;


      /*
        COMPONENTS

      */

      // COMPONENT INDEX
      const CPT_index = { 

        template: 
        `
        <!-- HTML PARENT CONTAINER -->
        <div style="background-color: #bcaaa4;">
          <strong>Component:</strong> CPT_index
          <br>
          <strong>Route :</strong> ./
          <br>
          <strong>Params:</strong> none
          <br>
          <button type="button" v-on:click="notify()">NOTIFY</button>
        </div>
        `,
        // COMPONENT SIGN IN - METHODS
        methods:{
          notify: function() {
            console.log('Hi! I am a method inside a local component CPT_index.');
          }
        }

      };

      // COMPONENT SIGN IN
      const CPT_sign_in = { 

        template: 
        `
        <!-- HTML PARENT CONTAINER -->
        <div style="background-color: #bcaaa4;">
          <strong>Component:</strong> CPT_sign_in
          <br>
          <strong>Route :</strong> ./sign-in
          <br>
          <strong>Params:</strong> none
          <br>
          <button type="button" v-on:click="notify()">NOTIFY</button>
        </div>
        `,
        // COMPONENT SIGN IN - METHODS
        methods:{
          notify: function() {
            console.log('Hi! I am a method inside a local component CPT_sign_in.');
          }
        }


      };

      // COMPONENT 404
      const CPT_404 = { 

        template: 
        `
        <!-- HTML PARENT CONTAINER -->
        <div style="background-color: #ef9a9a;">
          <strong>CPT_404</strong>
          <br>
          <strong>Route :</strong> ./404
          <br>
          <strong>Params:</strong> none
        </div>
        `
      }

      /*
        ROUTER

      */
      // VUE.JS ROUTER INSTANCE
      const router = new VueRouter({

      // IN THIS ROUTE I WILL RENDER THESE COMPONENTS..

        // ROUTER MODE - hash, history
        mode: 'hash',

        base: '/',

        // CSS FOR ROUTER-LINK ACTIVE
        linkActiveClass: "active",
        // CSS FOR ROUTER-LINK exact ACTIVE
        linkExactActiveClass: "exactActive",

        // ROUTES(S) TO EVALUATE IN ORDER
        routes: [

          /*
            ROUTES

          */
          // ROUTE INDEX
          { name: 'index',
            path: '/',
            // ROUTE(S) WITH COMPONENT(S) TO RENDER IN ORDER
            components: {
              // ONE OR MORE...
              RTV_index: CPT_index,
            }
          }, // END ROUTE INDEX

          // --------------------------------------------------------------------------------

          // ROUTE SIGN IN
          { name: 'sign_in',
            path: '/sign-in',
            // ROUTE(S) WITH COMPONENT(S) TO RENDER IN ORDER
            components: {
              // ONE OR MORE...
              RTV_sign_in: CPT_sign_in,
            }
          }, // END ROUTE SIGN IN

          // --------------------------------------------------------------------------------

          /*
            REDIRECT

          */
          // ROUTE REDIRECT
          { name: null,
            path: '*', redirect: { name: '404' },
            // TRAP ANY UNDEFINED ROUTE AND...
            // FORWARD IT TO /404 ROUTE
          }, // END ROUTE REDIRECT


          /*
            TO /404

          */
          // ROUTE 404
          { name: '404',
            path: '/404',
            // ROUTE COMPONENT(S) TO RENDER IN ORDER
            components: {
              // ONE OR MORE...
              RTV_404: CPT_404,
            }
          }, // END ROUTE 404

        ] // END ROUTES(S) TO EVALUATE IN ORDER

      });



      /*
       APP

      */
      // VUE.JS APP INSTANCE
      const App = new Vue({
        // ROOT ELEMENT
        el: '#app',
        // ROUTER
        router,

        /*
          DATA

        */
        // APP DATA (SINGLE SOURCE OF TRUTH)
        data: {
          data0: true,
          data1: 'Data1 - Rendered successfuly.',
          data2: 'Data2 - Rendered successfuly.',
          data3: 'Data3 - Rendered successfuly.',

        },

        /*
          COMPUTED

        */
        // COMPUTED PROPERTIES
        computed: {


        },

        /*
          METHODS

        */
        // APP METHODS
        methods:{
          //Initialize App.
          init: function() {
            
            console.log('App initialized.');

            if (this.supportsLocalSessionStorage()) {
              console.log('HTML5 localStorage & sessionStorage Supported.');
            } else {
              console.error('Fatal Error: No HTML5 localStorage & sessionStorage support.');
            }

          },

          // HTML5 Local & Session sotrage detection
          supportsLocalSessionStorage: function() {
            return typeof(Storage) !== 'undefined';
          },

          notify: function() {
            console.log('Hi! I am a method inside the parent instance App.');
          }

        }, // END APP METHODS

        /*
          HOOKS

        */
        // APP LIFE CYCLE HOOKS
        mounted(){
          this.$nextTick(function () {
            // Code that will run only after the
            // entire view has been rendered
            // Initialize App
            this.init();
          })

        }

      });


    </script>

  </body>

</html>

最佳答案

要实现您的目标,您只需更改:

<button type="button" v-on:click="notify()">NOTIFY</button>

<button type="button" v-on:click="$parent.notify()">NOTIFY</button>

但是,由于“父级”是 $root 组件,您实际上可以调用:

<button type="button" v-on:click="$root.notify()">NOTIFY</button>

这将解决以下使用 parent 的陷阱。调用 $parent 时,您正在耦合组件层次结构,这将使重用这些组件变得困难。您可能需要考虑使用 $emit 的事件驱动系统。

<button type="button" v-on:click="$emit('notify')">NOTIFY</button>

然后在任何父组件上,您将像这样收听“通知”:

mounted () {
  this.$on('notify', (event) => {
    // do something in your case it would be
    this.notify()
  })
}

您可能还需要考虑实现事件总线以从应用程序的任何位置捕获事件。

一个简单的例子是:

在 main.js 中添加:

Vue.prototype.$bus = new Vue

在组件中添加:

<button type="button" v-on:click="$bus.$emit('notify')">NOTIFY</button>

然后在您可以添加的任何其他组件中:

mounted () {
  this.$bus.$on('notify', (event) => {
    // do something in your case it would be
  })
}

希望这对您有所帮助!

关于javascript - 在组件内部单击按钮,调用父方法。如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57858356/

相关文章:

javascript - ul 样式仅在滚动时更改,返回滚动/更改点时会丢失样式

javascript - Function.prototype.call.bind 在此代码中的工作原理

javascript - vuejs v-model 让它只从一处改变

javascript - 如何从 vue.js 数据中获取值到另一个数据参数中

javascript - 重构 vue.js 中的方法

javascript - (VUEX + JEST) 函数响应未定义

vue.js - 如何使用 vue v3 项目将 boostrap v5 (js + css) 导入 nuxt.js v2.14?

javascript - 你如何命名用于 Vue.js 组件中的 exjection 的 Axios 拦截器?

vue.js - Vuejs 库 CLI v3 排除

javascript - 如何在尚未评估变量的情况下将变量传递给自定义组件?