Vue組件——子組件向父組件傳遞數據以及路由

自定義事件

咱們知道,父組件使用 prop 傳遞數據給子組件。但子組件怎麼跟父組件通訊呢?這個時候 Vue 的自定義事件系統就派得上用場了。php

使用 綁定自定義事件v-on

每一個 Vue 實例都實現了事件接口,即:html

  • 使用 $on(eventName) 監聽事件vue

  • 使用 $emit(eventName) 觸發事件ios

Vue 的事件系統與瀏覽器的 EventTarget API 有所不一樣。儘管它們的運行起來相似,可是 $on 和 $emit 並非addEventListener 和 dispatchEvent 的別名。vue-router

另外,父組件能夠在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件。
不能用 $on 偵聽子組件釋放的事件,而必須在模板裏直接用 v-on 綁定,參見下面的例子。npm

//定義子組件
var Child = {
//獲取data()中的數據,並添加一個點擊事件
    template: `<button @click="addCounter">{{counter}}</button>`,
    data(){
        return {
            counter: 0
        }
    },
    methods:{
        addCounter(){
            this.counter++;
            //自定義事件$emit傳回根組件,同時調用根組件方法
            this.$emit('add-parent-total')
        }
    }
}
//根組件
var vm = new Vue({
    el: "#app",
    data:{
        total: 0
    },
    components: {
        Child
    },
    methods: {
//根組件中子組件改變根組件的方法
        addTotal(){
            this.total++
        }
    }
})

//html
<child @add-parent-total="addTotal"></child>

使用插槽分發內容

注意兩點:axios

  • <app> 組件不知道它會收到什麼內容。這是由使用 <app> 的父組件決定的。api

  • <app> 組件極可能有它本身的模板。瀏覽器

爲了讓組件能夠組合,咱們須要一種方式來混合父組件的內容與子組件本身的模板。這個過程被稱爲內容分發 (即 Angular 用戶熟知的「transclusion」)。Vue.js 實現了一個內容分發 API,參照了當前 Web Components 規範草案,使用特殊的 <slot> 元素做爲原始內容的插槽。app

//slot插槽使其能夠在html中傳入數據,也能夠在其中傳入默認內容
var Child = {
    template: `<div>1 <slot>默認內容</slot></div>`
}
var vm = new Vue({
    el: "#app",
    components: {
        Child
    }
})

html
<child>hello</child>

有名slot

//slot插槽使其能夠在html中傳入數據,也能夠在其中傳入默認內容
var Child = {
    template: `<div>1 
    <slot name="header">header</slot>
    <slot>默認內容</slot>
    <slot name="footer">footer</slot>
    </div>`
}
var vm = new Vue({
    el: "#app",
    components: {
        Child
    }
})

html

<child>
    <div slot="header">頭部內容</div>
    22222
    <div slot="footer">底部內容</div>
</child>

非父子組件

有時候,非父子關係的兩個組件之間也須要通訊。在簡單的場景下,能夠使用一個空的 Vue 實例做爲事件總線:

var bus = new Vue()
        var AppHead = {
        template: '<div><button @click="add">添加<button></div>',
        methods: {
            add() {
                // 觸發組件A中的事件
                bus.$emit('change', 1)
            }
        }
    }
    var AppBody = {
        template: '<div>{{ counter }}</div>',
        data() {
            return {
                counter: 0
            }
        },
        created() {
            //在組件B建立的鉤子中監聽事件
            bus.$on('change', count => {
                this.counter += count
            })
        }
    } 
    var vm = new Vue ({
        el: '#app',
        components: {
            AppHead,
            AppBody
        }
    })

模態框實例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
      *{margin: 0;padding: 0;}
    html, body {
      height: 100%;
    }
    .dcj-modal {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.3);
    }
    .dcj-modal .dcj-modal-container {
      position: absolute;
      background: white;
      border: 1px dashed green;
      width: 300px;
      min-height: 200px;
      top: 50%;
      left: 50%;
      transform: translateX(-50%) translateY(-50%);
    }
    .dcj-modal .dcj-modal-container .dcj-modal-header {
      position: relative;
      line-height: 50px;
      text-align: center;
      border-bottom: 1px solid #ccc;
    }
    .dcj-modal .dcj-modal-container .dcj-modal-header button {
      position: absolute;
      right: 8px;
      top: 40%;
      transform: translateY(-50%);
    }
    .dcj-modal .dcj-modal-container .dcj-modal-body {
      padding: 8px;
    }
    .dcj-modal .dcj-modal-container .dcj-modal-footer {
      position: absolute;
      bottom: 0;
      width: 100%;
      height: 30px;
      text-align: center;
      line-height: 30px;
      border-top: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <div id="app">
    <button @click="openRegister">註冊</button>
    <button @click="openLogin">登陸</button>
    <modal v-show="showRegister" @close-modal="closeRegister">
        <p slot="header">註冊</p>
        <register></register>
        <p slot="footer">
            <input type="submit" value="註冊" form="register"/>
        </p>
    </modal>
    <modal v-show="showLogin" @close-modal="closeLogin">
        <p slot="header">登陸</p>
        <login></login>
        <p slot="footer">
            <input type="submit" value="登陸" form="login"/>
        </p>
    </modal>
  </div>
  <script src="vue.js" charset="utf-8"></script>
  <script>
      var Login = {
          template: `<form action="" id="login">
            用戶名: <input type="text" /><br>
            密&nbsp;&nbsp;&nbsp;碼:  <input type="password" /><br>

        </form>`
      }
      var Register = {
          template: `<form action="" id="register">
            用戶名: <input type="text" /><br>
            密&nbsp;&nbsp;&nbsp;碼:  <input type="password" /><br>
        </form>`
      }
    var Modal = {
      template: `<div class="dcj-modal" @click.self="closeModal">
        <div class="dcj-modal-container">
          <div class="dcj-modal-header">
            <slot name="header">title</slot>
            <button @click="closeModal">關閉</button>
          </div>
          <div class="dcj-modal-body">
            <slot>body</slot>
          </div>
          <div class="dcj-modal-footer">
            <slot name="footer">footer</slot>
          </div>
        </div>

      </div>`,
      methods: {
        closeModal() {
          this.$emit('close-modal');
        }
      }
    }
    var vm = new Vue({
      el: '#app',
      data: {
        showRegister: false,
        showLogin: false
      },
      methods: {
        openRegister() {
          this.showRegister = true
        },
        closeRegister() {
          this.showRegister = false
        },
        openLogin() {
          this.showLogin = true
        },
        closeLogin() {
          this.showLogin = false
        }
      },
      components: {
        Modal,
        Register,
        Login
      }
    })
  </script>
</body>
</html>

vue路由

對於大多數單頁面應用,都推薦使用官方支持的 vue-router 庫。更多細節能夠看 vue-router 文檔。

靜態路由

不須要複雜的路由

首先須要
npm i -S vue-router 安裝router庫
        var NewsComponent = { template: `<div>新聞</div>`}
        var ShopComponent = { template: `<div>商場</div>`}
        var NotFoundComponent = { template: `<div>404</div>`}
        var routes = [
            {
                path: '/',
                redirect: '/news'//默認根目錄跳轉
            },
            {
                path: '/news',
                component: NewsComponent
            },
            {
                path: '/shop',
                component: ShopComponent
            },
            {
                path: '*',
                component: NotFoundComponent
            }
        ]
        var router = new VueRouter({
            routes
        })
//        var app = new Vue({
//            el: "#app",
//            router
//        })

        var app = new Vue({
            el: "#app",
            router
        })

動態路由

var Goods = {
      template: `<div>
        <ul>
          <li v-for="(good, index) in goods" :key="'goods' + index">
            <img :src="good.goods_thumb" :alt="good.goods_name" :title="good.goods_name"/>
            {{ good.goods_name }}
            {{ good.price }}
          </li>
        </ul>
      </div>`,
      watch: {
        $route (to, from) {
          console.log(to.params.id);
          axios.get('http://h6.duchengjiu.top/shop/api_goods.php?cat_id='+to.params.id).then(res => {
            console.log(res.data.data)
            this.goods = res.data.data
          })
        }
      },
      data() {
        return {
          goods: []
        }
      }
    }
    var router = new VueRouter({
      routes: [
        { path: '/cat/:id', component: Goods }
      ]
    });
    var vm = new Vue({
      el: '#app',
      router,
      data: {
        cats: []
      },
      created() {
        axios.get('http://h6.duchengjiu.top/shop/api_cat.php').then(res => {
          console.log(res)
          this.cats = res.data.data
        })
      }
    });
相關文章
相關標籤/搜索