Vue组件之间的通信和路由

  • Post author:
  • Post category:vue




Vue组件之间的通信和路由



一、组件化

在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。

但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。

在vue里,所有的vue实例都是组件



1.1

全局组件

我们通过Vue的component方法来定义一个全局组件。

<div id="app">
    <!--使用定义好的全局组件-->
    <counter></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("counter",{
        template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
        data(){
            return {
                count:0
            }
        }
    })
    var app = new Vue({
        el:"#app"
    })
</script>
  • 组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
  • 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
  • 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
  • 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
  • data必须是一个函数,不再是一个对象。

效果:

在这里插入图片描述



1.2.组件的复用

定义好的组件,可以任意复用多次:

<div id="app">
    <!--使用定义好的全局组件-->
    <counter></counter>
    <counter></counter>
    <counter></counter>
</div>

效果:

在这里插入图片描述

你会发现每个组件互不干扰,都有自己的count值。怎么实现的?


组件的data属性必须是函数

当我们定义这个

<counter>

组件时,它的

data 并不是像之前直接提供一个对象

data: {
  count: 0
}

取而代之的是,

一个组件的 data 选项必须是一个函数

,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
  return {
    count: 0
  }
}

如果 Vue 没有这条规则,点击一个按钮就会影响到其它所有实例!



1.3

局部组件

一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。

因此,对于一些并不频繁使用的组件,我们会采用局部注册。



子组件中声明的各种需要的数据和方法:

普通组件:


  • template

    //定义子组件模板

  • props

    //通过props来接收一个父组件传递的数据,是一个数组。

  • methods

    //vue提供了一个内置的

    this.$emit()

    函数,用来调用父组件绑定的函数

vue-route 路由:


  • routes

    //里面有多个组件的

    path

    路由路径和

    component

    组件名称

    • 通过

      <router-link>

      指定一个跳转链接,当点击时,会触发vue-router的路由功能,路径中的hash值会随之改变
    • 通过

      <router-view>

      来指定一个锚点,当路由的路径匹配时,vue-router会自动把对应组件放到锚点位置进行渲染

我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:

const counter = {
    template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
    data(){
        return {
            count:0
        }
    }
};

然后在Vue中使用它:

var app = new Vue({
    el:"#app",
    components:{
        counter:counter // 将定义的对象注册为组件
    }
})
  • components就是当前vue对象子组件集合。

    • 其key就是子组件名称
    • 其值就是组件对象名
  • 效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用



1.4.组件通信

通常一个单页应用会以一棵嵌套的组件树的形式来组织:

在这里插入图片描述

  • 页面首先分成了

    顶部导航



    左侧内容区



    右侧边栏

    三部分

  • 左侧内容区

    又分为上下两个组件

  • 右侧边栏

    中又包含了3个子组件

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。



1.4.1 props(父向子传递)

  • 父向子传递:


    • 传递数据模型:需要通过自定义属性

    • 传递方法:需要通过自定义事例

      (子向父传递中用到)
  1. 父组件使用子组件时,自定义属性(

    属性名任意,属性值为要传递的数据

    )属性名需要通过

    v-bind

    方法进行绑定
  2. 子组件通过

    props

    接收父组件数据,通过自定义属性的属性名

父组件使用子组件,并自定义了title属性:

<div id="app">
    <h1>打个招呼:</h1>
    <!--使用子组件,同时传递title属性-->
    <introduce title="大家好,我是锋哥"/>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    Vue.component("introduce",{
        // 直接使用props接收到的属性来渲染页面
        template:'<h1>{{title}}</h1>',
        props:['title'] // 通过props来接收一个父组件传递的属性
    })
    var app = new Vue({
        el:"#app"
    })
</script>

效果:

在这里插入图片描述



1.4.2 props验证

我们定义一个子组件,并接收复杂数据:

    const myList = {
        template: '\
        <ul>\
        	<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
        </ul>\
        ',
        props: {
            items: {
                type: Array,
                default: [],
                required: true
            }
        }
    };
  • 这个子组件可以对 items 进行迭代,并输出到页面。
  • props:定义需要从父组件中接收的数据

    • items:是要接收的属性名称

      • type:限定父组件传递来的必须是数组
      • default:默认值
      • required:是否必须


当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

我们在父组件中使用它:

<div id="app">
    <h2>课程如下:</h2>
    <!-- 使用子组件的同时,传递属性,这里使用了v-bind,指向了父组件自己的属性lessons -->
    <my-list :items="lessons"/>
</div>
var app = new Vue({
    el:"#app",
    components:{
        myList // 当key和value一样时,可以只写一个
    },
    data:{
        lessons:[
            {id:1, name: 'java'},
            {id:2, name: 'php'},
            {id:3, name: 'ios'},
        ]
    }
})

效果:

在这里插入图片描述

type类型,可以有:

在这里插入图片描述



1.4.3 子向父的通信:$emit

来看这样的一个案例:

<div id="app">
    <h2>num: {{num}}</h2>
    <counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
     Vue.component("counter", {
            template:'\
                <div>\
                    <button @click="plus">加</button>  \
                    <button @click="reduce">减</button>  \
                </div>',
            props:['count'],
            methods:{
                plus(){
                    this.$emit("inc");
                },
                reduce(){
                    this.$emit("dec");
                }
            }
        })
    var app = new Vue({
    	el:"#app",
    	data:{
        	num:0
	    },
    	methods:{ // 父组件中定义操作num的方法
        	increment(){
            	this.num++;
	        },	
    	    decrement(){
	       	    this.num--;
    	    }
    	}
	})
</script>
  • 子组件接收父组件的num属性

  • 子组件定义点击按钮,点击后对num进行加或减操作

  • vue提供了一个内置的

    this.$emit()

    函数,用来调用父组件绑定的函数

效果:

在这里插入图片描述



二、路由 vue-router



2.1.场景模拟

现在我们来实现这样一个功能:

一个页面,包含登录和注册,点击不同按钮,实现登录和注册页切换:

在这里插入图片描述
在这里插入图片描述



2.1.1.编写父组件

为了让接下来的功能比较清晰,我们先新建一个文件夹:src

然后新建一个HTML文件,作为入口:index.html

在这里插入图片描述

然后编写页面的基本结构:

<div id="app">
    <span>登录</span>
    <span>注册</span>
    <hr/>
    <div>
        登录页/注册页
    </div>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app"
    })
</script>

样式:

在这里插入图片描述



2.1.2.编写登录及注册组件

接下来我们来实现登录组件,以前我们都是写在一个文件中,但是为了复用性,开发中都会把组件放入独立的JS文件中,我们新建一个user目录以及login.js及register.js:

在这里插入图片描述

编写组件,这里我们只写模板,不写功能。

login.js内容如下:

const loginForm = {
    template:'\
    <div>\
    <h2>登录页</h2> \
    用户名:<input type="text"><br/>\
    密码:<input type="password"><br/>\
    </div>\
    '
}

register.js内容:

const registerForm = {
    template:'\
    <div>\
    <h2>注册页</h2> \
    用&ensp;户&ensp;名:<input type="text"><br/>\
    密&emsp;&emsp;码:<input type="password"><br/>\
    确认密码:<input type="password"><br/>\
    </div>\
    '
}



2.1.3.在父组件中引用

<div id="app">
    <span>登录</span>
    <span>注册</span>
    <hr/>
    <div>
        <!--<loginForm></loginForm>-->
        <!--
            疑问:为什么不采用上面的写法?
            由于html是大小写不敏感的,如果采用上面的写法,则被认为是<loginform></loginform>
            所以,如果是驼峰形式的组件,需要把驼峰转化为“-”的形式
         -->
        <login-form></login-form>
        <register-form></register-form>
    </div>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="user/login.js"></script>
<script src="user/register.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: "#app",
        components: {
            loginForm,
            registerForm
        }
    })
</script>

效果:

在这里插入图片描述



2.2 vue-router 简介和安装

使用vue-router和vue可以非常方便的实现复杂单页应用的动态路由功能。

官网:

https://router.vuejs.org/zh-cn/


使用npm安装:

npm install vue-router --save


在这里插入图片描述
在index.html中引入依赖:

<script src="../node_modules/vue-router/dist/vue-router.js"></script>



2.3 快速入门

新建vue-router对象,并且指定路由规则:

// 创建VueRouter对象
const router = new VueRouter({
    routes:[ // 编写路由规则
        {
            path:"/login", // 请求路径,以“/”开头
            component:loginForm // 组件名称
        },
        {
            path:"/register",
            component:registerForm
        }
    ]
})
  • 创建VueRouter对象,并指定路由参数
  • routes:路由规则的数组,可以指定多个对象,每个对象是一条路由规则,包含以下属性:

    • path:路由的路径
    • component:组件名称

在父组件中引入router对象:

var vm = new Vue({
    el:"#app",
    components:{// 引用登录和注册组件
        loginForm,
        registerForm
    },
    router // 引用上面定义的router对象
})

页面跳转控制:

<div id="app">
    <!--router-link来指定跳转的路径-->
    <span><router-link to="/login">登录</router-link></span>
    <span><router-link to="/register">注册</router-link></span>
    <hr/>
    <div>
        <!--vue-router的锚点-->
        <router-view></router-view>
    </div>
</div>
  • 通过

    <router-link>

    指定一个跳转链接,当点击时,会触发vue-router的路由功能,路径中的hash值会随之改变
  • 通过

    <router-view>

    来指定一个锚点,当路由的路径匹配时,vue-router会自动把对应组件放到锚点位置进行渲染

效果:

在这里插入图片描述
在这里插入图片描述


注意

:单页应用中,页面的切换并不是页面的跳转。仅仅是地址最后的hash值变化。

事实上,我们总共就一个HTML:index.html



版权声明:本文为Xxacker原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。