组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的 组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。
组件化和模块化的不同:
模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能 模块的职能单一。
组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用
在组件中,data需要被定义为一个方法,将data设置为一个函数,而不是一个对象的原因是实现深拷贝,实现数据分离,各个数据之间相互独立,互不影响,如下图的计算器组件。``
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<body>
<div id ="app">
<course></course>
<course></course>
<course></course>
<course></course>
<!-- <login></login> -->
</div>
<div id="app2">
<login></login>
</div>
<template id="course">
<div>
<div>课程组件</div>
<div>{{num}}</div>
<button @click='add1'>点我加一</button>
</div>
</template>
<script>
// 使用components属性定义全局组件
Vue.component("course",{
template:"#course",
// 将data设置为一个函数,而不是一个对象的原因是实现深拷贝,实现数据分离,各个数据之间相互独立
// 深拷贝:传值。
data(){
return {
num:13,
};
},
methods:{
add1(){
this.num++;
},
}
})
const vm = new Vue({
el: '#app',
data: {},
methods: {}
});
const vm2 = new Vue({
el: '#app2',
data: {},
methods: {},
// 使用components属性定义局部组件
components:{
login:{
template:"登录/注册
",
data(){
return {
num2:45,
}
}
},
},
});
</script>
</body>
</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>Documenttitle>
<script src="./vue-2.4.0.js">script>
<body>
<temp1name>temp1name>
<temp2name>temp2name>
<temp3name>temp3name>
<temp4name>temp4name>
div>
<script id="num3" type="x-template">
<!-- 只能有一个根元素 -->
<h3>我是声明组件方法三
<div>第一个盒子</div>
<div>第二个盒子</div>
</h3>
script>
<template id="num4">
<div>我是声明组件方法四:最常用的方法div>
template>
<script>
//创建Vue实例,得到 ViewModel
// 方法一:使用 Vue.extend 配合 Vue.component 方法:
// 第一步:声明组件
let temp1=Vue.extend({
template:"我是声明组件方法一
"
});
// 第二步:全局注册组件:Vue.component(参数一是名字,参数二是模版),当作标签来使用
Vue.component("temp1name",temp1)
// 方法二:直接使用 Vue.component 方法
Vue.component("temp2name",{
template:"我是声明组件方法二
"
})
// 方法三:将模板字符串,定义到script标签中:添加type的属性值为x-template。
// 定义模板
Vue.component("temp3name",{
template:"#num3"
})
// 方法四:最常用得方法。将模板字符串,定义到template标签中:
Vue.component("temp4name",{
template:"#num4",
})
// 注意:
// 不能使用驼峰命名法
// 不要使用内置或保留得HTML元素作为组件id"footer"
// 只能有一个根元素
const vm = new Vue({
el: '#app',
data: {},
methods: {}
});
script>
body>
html>
四、使用flag标识符结合v-if和v-else切换组件
<!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>
<script src="./vue-2.4.0.js"></script>
<body>
<div id ="app">
<button @click="flag=!flag">点我切换组件生死</button>
<login v-if="flag"></login>
<register v-else></register>
<!-- 使用component标签,来引用组件,并通过:is属性来指定要加载的组件: -->
<componets is="login"> </componets>
<!-- 也可以通过绑定data中的属性 -->
<componets :is="name"> </componets>
<componets is="register"> </componets>
</div>
<template id="login">
<div>登录</div>
</template>
<template id="register">
<div>注册</div>
</template>
<script>
Vue.component("login",{
template:"#login",
data(){
return {
};
},
methods:{},
created(){},
beforeDestroy() {
console.log("我要没了");
},
destroyed() {
console.log("我没了");
},
})
Vue.component("register",{
template:"#register",
data(){
return {
};
},
methods:{},
created(){
},
})
//创建Vue实例,得到 ViewModel
const vm = new Vue({
el: '#app',
data: {
flag: true,
name:"login"
},
methods: {}
});
</script>
</body>
</html>
五、 使用:is属性来切换不同的子组件,并添加切换动画。
<!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>
<script src="./vue-2.4.0.js"></script>
<style>
/* 添加切换样式: */
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(30px);
}
.v-enter-active,
.v-leave-active {
position: absolute;
transition: all 1.3s ease;
}
h3 {
margin: 0;
}
</style>
<body>
<div id ="app">
<button @click="comName='login'">登录</button>
<button @click="comName='register'">注册</button>
<div>
<!-- mode='out-in':设置两个字的动画,一个出另一个进,或者一个进另一个出。 -->
<transition mode='out-in'>
<!-- 使用component标签,来引用组件,并通过:is属性来指定要加载的组件: -->
<components :is='comName'></components>
</transition>
</div>
</div>
<template id="login">
<div>登录</div>
</template>
<template id="register">
<div>注册</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
Vue.component("login",{
template:"#login",
data(){
return {
};
},
methods:{},
})
Vue.component("register",{
template:"#register",
data(){
return {
};
},
methods:{},
created(){
},
})
const vm = new Vue({
el: '#app',
data: {
//定义comName的数据,默认页面上显示的时登录模块。
comName:"login"
},
methods: {}
});
</script>
</body>
</html>
六-1、父组件传值子组件
接受父组件传值
设置props属性就可以接受父组件传值
天亮云课堂父子传值代码示例:
<!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>云课堂一</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./vue-2.4.0.js"></script>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
a {
color: black;
text-decoration: none;
}
a:hover {
color: red;
}
ul {
list-style: none;
}
/* 免费课程 */
.freeClass {
position: relative;
margin: 20px auto 0px;
width: 1200px;
text-align: center;
}
.freeClass>h2 {
margin: 0 auto;
width: 100%;
height: 50px;
font-size: 24px;
color: #333;
font-weight: normal;
display: inline-block;
border-bottom: 2px solid #e8e8e8;
}
.freeClass>a {
position: absolute;
/* top: 10px; */
right: 10px;
}
.freeClass-list {
/* overflow: hidden; */
box-sizing: border-box;
}
.freeClass-list>li {
float: left;
margin-top: 20px;
width: 20%;
padding: 0px 10px;
text-align: left;
}
.freeClass-list>li>div {
margin-bottom: 8px;
width: 100%;
height: 123px;
overflow: hidden;
}
.freeClass-list>li>div>img {
width: 100%;
height: 100%;
}
.freeClass-list>li>p {
font-size: 14px;
height: 24px;
}
.freeClass-list>li>span {
color: #888;
}
.freeClass-list>li>p:nth-of-type(2) {
/* height: 27px; */
color: #00cf8c;
font-size: 16px;
}
.freeClass-list>li>div>img:hover {
transform: scale(1.1,1.1);
/* transition-delay: 10s; */
}
</style>
<body>
<div id ="app">
<index></index>
</div>
<script>
Vue.component("index",{
template:"#index",
})
</script>
<template id="index">
<div>
<course type="free" pagesize="10" pagenum="2">免费课程</course>
<course type="boutique" pagesize="5" pagenum="1">精品课程</course>
<course type="discount" pagesize="5" pagenum="3">限时折扣课程</course>
</div>
</template>
<template id="course">
<div>
<section class="freeClass">
<h2>
<!-- 普通插槽 -->
<slot></slot>
</h2>
<a href="">更多</a>
<ul class="freeClass-list" v-for="(item,index) in courseList" :key="item.id">
<li>
<div><img class="courseImg" alt="" :src="item.coverFileUrl"></div>
<p>{{item.courseTitle}}</p>
<span>共{{item.learningNum}}节课|{{item.participationsCount}}人报名</span>
<p>免费</p>
</li>
</ul>
</section>
</div>
</template>
<script>
Vue.component("course",{
template:"#course",
data(){
return {
courseList: [],
};
},
props:{
//type: String
type:[String,Number],
pagenum: [String, Number],
pagesize: [String, Number],
},
created(){
console.log(this.type);
console.log(this.pagenum);
this.getCourseList(this.type,this .pagesize,this.pagenum)
},
// 根据不同的参数类型获取不同的课程列表
methods:{
getCourseList(type,pageSize,pageNum){
let form = new FormData();
form.append("type", type);
form.append("pageSize", pageSize);
form.append("pageNum", pageNum);
axios
.post(
"http://wkt.myhope365.com/weChat/applet/course/list/type",
form
)
.then((res) => {
console.log(res);
this.courseList = res.data.rows;
});
}
}
})
</script>
<script>
//创建Vue实例,得到 ViewModelnt
const vm = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
</body>
</html>
六-2、子组件传值父组件
子组件调用父组件的方法
1>.在父组件中给引用的子组件注册一个事件(这个事件的名字是自定义的)
2>.子组件可以触发这个事件$emit(‘事件名字’)
子组件给父组件传递数据
1>.$emit方法第二个参数可以定义子组件给父组件传递的内容
2>.在父组件中怎么拿到这内容
a、父组件这个方法没有自定参数,在父组件的方法直接加这个参数就可以拿到
b、父组件有自定义参数,可以传入也可以(event)拿到子组件传递的数据,只能传递第一个参数。
代码示例:
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<body>
<div id ="app">
<father></father>
</div>
<template id="father">
<div>
<h2>我是父组件哈哈哈哈</h2>
<!-- 1.在父组件中给引用的子组件注册一个事件(这个事件的名字是自定义的) -->
<son @fromto='fromson'></son>
这是子组件传过来的{{msg}}
</div>
</template>
<template id="son">
<div>
<h2>我是子组件啊啦啦啦啦</h2>
<button @click='tofather'>点击向父组件传值</button>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
Vue.component("father",{
template:"#father",
data(){
return {
msg:"",
};
},
methods:{
//2>.父组件拿到这内容:
// 父组件这个方法没有自定参数,在父组件的方法直接加这个参数就可以拿到
// 父组件有自定义参数,可以传入$event也可以拿到子组件传递的数据。通过$event只能传递第一个参数。
fromson(data){
console.log(data);
this.msg=data;
}
}
});
Vue.component("son",{
template:"#son",
data(){
return {
num1:1245,
}
},
methods: {
tofather(){
console.log(66666);
// 2.子组件触发这个事件$emit('事件名字')
// 子组件给父组件传递数据
// 1>$emit方法第二个参数可以定义子组件给父组件传递的内容
this.$emit("fromto",this.num1)
},
}
})
const vm = new Vue({
el: '#app',
data: {},
});
</script>
</body>
</html>
七、 Vue中路由的使用:
1 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源
2 前端路由:对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
3 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由)
如何使用路由
路由的基本使用:
1> 引入js文件,这个js需要放在vue的js后面,自动安装(提供了一个VueRouter的构造方法)
2> 创建路由new VueRouter(),接受的参数是一个对象
3> 在实例化的对象里配置属性routes:[],这个数组里的对象包含path属性和component属性
4> path属性是url的地址,component属性就是显示的组件(传组件的对象)
5> 创建的路由需要和vue实例关联一下
6> 路由到的组件显示在哪个位置
代码实例:
<!DOCTYPE html>
<html>
<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></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--1. 引入vuerouter -->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<!-- 5? 预留展示区域 -->
<router-view></router-view>
</div>
<template id="son">
<div>
子组件
</div>
</template>
<script>
let son = Vue.component("son",{
template:"#son"
})
// 2创建实例
const router = new VueRouter({
// 3 .创建组件和路由映射关系
routes: [
{
path: "/",
component: Vue.component("haha", { template: "hahah
" }),
},{
path:"/son",
component:son
}
],
});
const vm = new Vue({
el: "#app",
data: {},
methods: {},
//4. 创建联系,挂载在Vue实例上
router,
});
</script>
</body>
</html>
路由的跳转
1router-link标签可以设置to属性
2默认是a标签,可以通过tag设置包裹标签
路由重定向
redirect可以进行路由的重定向
选中路由高亮
1.使用默认的样式
直接设置router-link-active
2.自定义样式
配置 linkActiveClass:‘自定义的类名’
代码实例:
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--1. 引入vuerouter -->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
.router-link-active{
color: red;
font-size: 40px;
}
.suibian{
color: hotpink;
font-size: 30px;
}
</style>
<body>
<!-- 父组件 父子组件时相对的-->
<div id ="app">
<!-- 五.预留展示区域 路由到的组件所显示的位置-->
<router-view></router-view>
</div>
<template id="son">
<div>我是子组件呀呀呀呀呀呀
<router-link to="/son">点击去子组件</router-link>
<router-link to="/index">点击去父组件</router-link>
</div>
</template>
<template id="father">
<div>这是首页
<!-- 1。router-link标签可以设置to属性
2。默认是a标签,可以通过tag设置包裹标签 -->
<router-link to="/son">点击去子组件</router-link>
<router-link to="/son">点击去子组件</router-link>
<router-link to="/son" tag="div">去子组件tag改变标签</router-link>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
let son=Vue.component("son",{
template:"#son",
});
// Vue.component可以省略
let father={
template:"#father"
}
// 二.创建路由实例
const router=new VueRouter({
// 三.创建路由和组件的映射关系
routes:[
// 第一个路由和组件的映射关系
{
path:"/index",
component:father,
},
// 第一个路由和组件的映射关系
// redirect可以进行路由的重定向 :当为"/"定向到index页面,不用先到地址栏上拼接才能切换到index页面,
// 如果定向的是son,那么当为"/"时,默认显示的时son的页面
{ path: "/", redirect: "/index" },
{
path:"/son",
component:son,
},
],
// 1.使用默认的样式
// 直接设置router-link-active
//2、使用自定义样式
linkActiveClass:"suibian"
})
const vm = new Vue({
el: '#app',
data: {},
methods: {},
//四. 创建路由实例和vue实例联系,将路由实例挂载在Vue实例上
// router:"roeter",ES6当属性值和属性重复时可以省略
router,
});
</script>
</body>
</html>
八、路由定义参数
1、通过query的方式在url后加?参数名=参数的值
获取参数:$route.query.参数名
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--1. 引入vuerouter -->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
</style>
<body>
<!-- 父组件 父子组件时相对的-->
<div id ="app">
<!-- 5.预留展示区域 路由到的组件所显示的位置-->
<router-view></router-view>
</div>
<template id="son">
<div>我是子组件呀呀呀呀呀呀
<router-link to="/index">点击去父组件</router-link>
<!-- 路由传参 -->
<router-link :to="{path:'index',query:{sondataid:888}}">点击去父组件路由传参1</router-link>
<router-link :to="{path:'index',query:{sondata:sondataid}}">点击去父组件路由传参2</router-link>
</div>
</template>
<template id="father">
<div>这是首页
<!-- 1。router-link标签可以设置to属性
2。默认是a标签,可以通过tag设置包裹标签 -->
<router-link to="/son">点击去子组件</router-link>
<router-link to="/son" tag="div">去子组件tag改变标签</router-link>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
let son=Vue.component("son",{
template:"#son",
data(){
return {
sondataid:104,
};
},
});
// Vue.component可以省略
let father={
template:"#father",
created(){
console.log(this.$route);
console.log(this.$route.query);
}
}
// 2.创建路由实例
const router=new VueRouter({
// 3.创建路由和组件的映射关系
routes:[
// 第一个路由和组件的映射关系
{
path:"/index",
component:father,
},
// 第一个路由和组件的映射关系
// redirect可以进行路由的重定向 :当为"/"定向到index页面,不用先到地址栏上拼接才能切换到index页面,
// 如果定向的是son,那么当为"/"时,默认显示的时son的页面
{ path: "/", redirect: "/index" },
{
path:"/son",
component:son,
},
],
})
const vm = new Vue({
el: '#app',
data: {},
methods: {},
//4. 创建路由实例和vue实例联系,将路由实例挂载在Vue实例上
// router:"roeter",ES6当属性值和属性重复时可以省略
router,
});
</script>
</body>
</html>
2、使用浏览器参数的方式传递参数
1>.设置路由的时候/路由地址/:参数名
2>.获取参数$route.params.参数名
代码实例:
<!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>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--1. 引入vuerouter -->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
</style>
<body>
<!-- 父组件 父子组件时相对的-->
<div id ="app">
<!-- 5.预留展示区域 路由到的组件所显示的位置-->
<router-view></router-view>
</div>
<template id="son">
<div>我是子组件呀呀呀呀呀呀
<router-link to="/index">点击去父组件</router-link>
<!-- 路由传参 -->
<router-link :to="{path:'index',query:{course:888}}">点击去父组件路由传参1</router-link>
<router-link :to="{path:'index',query:{course:courseid}}">点击去父组件路由传参2</router-link>
</div>
</template>
<template id="father">
<div>这是首页
<!-- 1。router-link标签可以设置to属性
2。默认是a标签,可以通过tag设置包裹标签 -->
<!-- <router-link to="/son">点击去子组件</router-link> -->
<router-link :to="{name:'son',params:{id:111}}">点击去子组件路由传参1</router-link>
<router-link :to="{name:'son',params:{id:fatherdata,name:'李四'}}">点击去子组件路由传参1</router-link>
<router-link to="/son" tag="div">去子组件tag改变标签</router-link>
</div>
</template>
<script>
//创建Vue实例,得到 ViewModel
let son=Vue.component("son",{
template:"#son",
data(){
return {
courseid:104,
};
},
created(){
console.log(this.$route);
console.log(this.$route.params);
}
});
// Vue.component可以省略
let father={
template:"#father",
data(){
return{
fatherdata:"666",
}
},
}
// 2.创建路由实例
const router=new VueRouter({
// 3.创建路由和组件的映射关系
routes:[
// 第一个路由和组件的映射关系
{
path:"/index",
component:father,
},
// 第一个路由和组件的映射关系
// redirect可以进行路由的重定向 :当为"/"定向到index页面,不用先到地址栏上拼接才能切换到index页面,
// 如果定向的是son,那么当为"/"时,默认显示的时son的页面
{ path: "/", redirect: "/index" },
{
// 定义必传参数
path:"/son/:id/:name",
component:son,
name:"son",
},
],
})
const vm = new Vue({
el: '#app',
data: {},
methods: {},
//4. 创建路由实例和vue实例联系,将路由实例挂载在Vue实例上
// router:"roeter",ES6当属性值和属性重复时可以省略
router,
});
</script>
</body>
</html>