一、组件(最基本的能力)
1、vue组件的定义
在页面引入的组件同时也是Vue的实例(如:<mycom1></mycom1> )
- 什么是模块化:模块化从代码角度出发,分析项目,把项目中功能类似的代码抽离为一个个小的模块,为了以相同的方式去封装模块,于是就创造了模块化的规范(CommonJS规范)
- 优点:方便项目的开发,方便后期的维护和扩展 ,提高开发效率
- 什么是组件化:从UI的角度出发,把页面上有重用性的UI结构和样式,单独抽离出来,封装为一个单独的组件(封装的是HTML元素),每个组件是一个自定义的元素
- 优点:随着项目的发展,组件会越来越多,今后一个界面的UI几乎都可以从现成的组件拼接出来,方便项目的开发和维护
- 注意:组件也有自己的生命周期函数,这些函数与vm实例的生命周期一致
- 最常用.vue文件来使用组件(单独一个组件文件,实现组件化)
2、全局组件定义的方式
第一种:
(1)使用Vue.component 注册一个组件:
Vue.component('mycom2',{
template:'<h2>这是直接使用Vue.component创建出的组件</h2>'
});
(2)把注册好的全局组件标签以标签的形式引入到页面中
<div id="app">
<mycom1></mycom1>
</div>
第二种:
(1)使用template 标签定义一个模板的代码结构:
<template id="tmpl">
<h3>哈哈哈,这是在外界定义的组件UI结构</h3>
</template>
注意:
template 标签应该放在与id='app’的盒子平级的地方template 如果放在#app里面,则组件会被注册两次,元素会被渲染两次- 如果直接写为下面这样,则没有效果(因为组件已经不在Vue实例vm控制的区域内)
<mycom3></mycom3>
<template id="tmpl">
<h3>哈哈哈,这是在外界定义的组件UI结构</h3>
</template>
(2)使用Vue.component 注册组件:
Vue.component('mycom3',{
template:'#tmpl'
})
(3)把注册好的全局组件标签以标签的形式引入到页面中
3、定义私有组件
(1)在Vue实例中的定义私有组件(包含组件的名称和组件的结构):
components:{
'mycom4':{
template:"<h6>这是定义的私有组件</h6>"
}
}
(2)把注册好的全局组件标签以标签的形式引入到页面中
4、在组件中定义私有数据和方法(组件中展示数据和响应事件)
Vue.component('mycom',{
template:"<h3 v-on:click='show'>这是自定义的组件{{msg}}</h3>",
data:function(){
return {
msg:'hhh'
}
},
methods:{
show(){
console.log('触发了组件的show方法');
}
}
})
注意:
- 添加
data 属性时,data 必须定义为function且必须返回一个对象 - 为什么必须定义成function呢?
因为这样的话,每当我们在页面中引用一次组件,必须会先调用这个data:function ,从而得到一个当前组件私有的数据对象(保证每个组件的data是私有的) - 为什么必须返回一个对象?
每创建一个实例时调用function,返回一个新对象,新对象与之前创建的实例指向的对象无关系。如果返回的是在全局定义的对象,则每次创建的实例都会指向这个对象,即共用一个返回对象,其中一个实例的指向的对象的值改变时,所有实例指向的对象的值都会随之改变(数据联动)
5、组件的切换
1.两个组件的简单切换: 使用v-if 和v-else 、标识符、布尔值结合实现两个组件的切换 2.多个组件的切换
6、父组件与子组件传值问题
1.父组件向子组件传递普通数据:
(1)把要传递给子组件的数据作为自定义属性,通过v-bind 绑定到子组件身上:
<com1 :msg="parentMsg"></com1>
(2)在子组件中不能直接使用父组件传递过来的数据,需要使用props 将数据接收一下:
data:{
parentMsg:"哈哈哈,你是想笑死我,然后继承我的蚂蚁花呗吗?"
},
components:{
'com1':{
template:`<div>
<h3>这是子组件中的标题{{msg}}</h3>
</div>`,
props:['msg']
}
}
注意:
- 在接收父组件传递过来
props 时候,接受的名称一定要和父组件传递过来的自定义属性名称保持一致
2.父组件向子组件传递对象:
3.父组件向子组件传递方法:
注意:
- 如果要向子组件传递data中的数据,则使用属性绑定的形式
v-bind - 如果要向子组件传递methods中的数据,则使用事件绑定的形式
v-on
4.子组件向父组件传值:
子组件向父组件传值,本质上,还是调用了父组件传递过来的方法(show方法),只不过,子组件在调用的时候,把数据当作参数传给了这个方法(show方法) (1)把要传递给子组件的方法作为事件,通过v-on 绑定到子组件身上:
<com1 @func='show'></com1>
(2)为子组件添加自己的触发事件,并传值给父组件:
methods:{
show(){
console.log("有人调用了父组件中的show方法");
}
},
components:{
'com1':{
template:`<div>
<input type='button' value='点击子组件' @click="btnClick">
</div>`,
data:function(){
return{sonMsg:"这是子组件中的值"}
}
methods:{
this.$emit('func',sonMsg);
}
}
}
}
(3)父组件接收这个参数(值):
data:{
msgFromSon:''
},
methods:{
show(arg1){
this.msgFromSon = arg1;
console.log(this.msgFromSon);
}
},
5.在Vue组件中data和props的区别:
- 1、data在组件要定义成function并返回一个对象
- 2、props在组件中定义成数组,数组的值都是字符串名,表示父组件传递过来的数据
- 3、props的数据不要直接拿来修改,如果想要修改,必须在data上重新顶一个属性,然后把属性的值从this.props拿过来修改
- 4、data上的数据都是组件私有的,data上的数据都是可读可写的
- 5、props上的数据都是外界传过来的数据,只能读不能写
二、路由
1、什么是路由?
- 1、对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源
- 2、对于单页面的程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容,所以,单页面程序中的页面跳转主要用hash实现
- 3、在单页面程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由)
- 4、前端路由就是根据不同的hash地址展示不同的组件
- 5、后短路由:把后端地址URL地址与处理函数之间做一层对应关系
- 6、#叫做hash,不会刷新页面,也不会发起新的HTTP请求,只是实现客户端页面的定位的(因为#后面的值不会传给服务端)
- 7、#可以修改浏览器端的历史访问记录
2、Vue中的路由:v-router
路由的基本使用: (1)在导入vue包后导入vue-router的包:
<script src="./lib/vue-router-v3.0.1.js"></script>
(2)创建对应的组件:
const login = {
template:'<h3>登陆组件</h3>'
}
const reg = {
template:'<h3>注册组件</h3>'
}
注意:
- 不能再利用之前的方法创建组件了,因为之前创建的组件的组件名仅限于以标签的形式引入页面中,不能用于匹配路由规则,所以把对象单独拎出来
(3)创建路由对象:
const router = new VueRouter({
routes:[
{path:"/login", component:login},
{path:"/reg", component:reg}
]
})
注意:
routes :是固定属性,表示路由规则数组----把hash值和组件做对应关系,且每个对象都表示一个路由规则- 对象中的属性:path 表示要匹配的hash值,component 表示对应的hash要展示的组件对象
component 的属性不能传字符串,只能传一个对象- 匹配到的路由组件如果想要展示在页面上,需要在页面上放一个标签
router-view (路由的坑)
(4)将路由对象挂载在Vue实例中 (5)利用路由的坑(容器),将对应的路由组件填到坑中:
<div id="app">
<router-link to="/login">登录</router-link>
<router-link to="/reg">注册</router-link>
<router-view></router-view>
</div>
注意:
router-link :路由链接,默认渲染为a标签,也有tag属性router-view :默认不会被渲染为元素
总结: 路由匹配过程:点击不同的路由标签修改hash值,hash值被修改后,被路由规则监听到,然后匹配对应的路由规则 路由的目的:监听hash值的改变,根据路由规则,匹配对应的路由规则,展示对应的路由组件
3、在路由中传参
(1)query传参:优点:不需要修改路由规则
<router-link to="/login?id=10">登录</router-link>
获取参数:
template:'<h3>登陆组件----{{$route.query.id}}</h3>',
(2)/ 传参:需要修改路由规则,与node的express的传参和获取参数一致
<router-link to="/login/10/zs">登录</router-link>
修改路由规则:
{path:'/login/:id/:name', component: login}
获取参数:
template:'<h3>登陆组件----{{$route.params.id}}----{{$route.params.name}}</h3>',
(3)/ 传参时为了方便使用props 获取参数:
在组件中使用$route 会使参数和对应的路由形成高度的耦合 使用props 解耦:
const login = {
props:['id','name'],
template:'<h3>登陆组件----{{id}}----{{name}}</h3>',
}
const router = new VueRouter({
routes:[
{path:'/login/:id/:name', component:login, props:true},
4、vue-router 的重点内容
v-router 是实现前端路由的- 什么是前端路由:根据不同的hash地址,在页面上切换不同的组件(hash地址和组件的对应关系)
- 什么是后端路由:是URL地址和处理函数之间的对应关系
- 前端路由的目的:为了做单页面应用程序(Single Page Application)
- 学习前端框架的主要目的:就是利用这些现成的框架,方便我们快速进行单页面程序的开发【实现单页面应用程序的基本前提:要有vue的路由、组件】
5、使用路由规则的children 属性实现路由和组件的嵌套
实现路由组件的嵌套:
(1)在父路由的组件中创建子路由链接和子路由容器
const account = {
template:`<div class='account'>
<h1>这是Account账号组件</h1>
<!--创建子路由链接-->
<router-link to="/account/login">登录</router-link>
<router-link to="/account/reg">注册</router-link>
<!--子路由容器-->
<router-view></router-view>
</div>`
}
(2)创建account路由规则的子路由规则:
const router = new VueRouter({
routes:[
{path:'/account', component:account, children:[
{path:'login',component:login},
{path:'reg',component:reg},
]},
]
})
注意:
- 如果账号组件和登陆组件的路由规则是平级的,则会在页面的同一个路由的容器中显示,不会形成嵌套
如:
routes:[
{path:'/account',component:account},
{path:'/account/login',component:login},
- 通过路由规则的
children 属性,实现路由规则的嵌套,这样,组件之间也有了嵌套关系
6、命名视图
- 为什么需要命名视图:在之前的路由规则,当匹配带一个路由规则时,只能在页面的路由的容器中放置唯一一个组件(因为一个路径无法展示多个组件),此时需要命名视图,在一个URL地址中展示多个组件
- 什么时候用到命名视图:当在一层路由规则中需要展示多个组件时
(1)使用components :
{path:'/',components:{
'top':header,
'left':sidebar,
'right':content,
'bottom':footer
}}
(2)在router-view 中使用name 属性为不同组件命名:
<router-view name='top'></router-view>
<div class="container">
<router-view name='left'></router-view>
<router-view name='right'></router-view>
</div>
<router-view name='bottom'></router-view>
}}
(2)在router-view 中使用name 属性为不同组件命名:
<router-view name='top'></router-view>
<div class="container">
<router-view name='left'></router-view>
<router-view name='right'></router-view>
</div>
<router-view name='bottom'></router-view>
|