Vue框架(三)
一、组件
1、组件声明
全局组件需要再main.js中声明:
//导入vue.js
import Vue from 'vue'
//导入根组件
import App from './App.vue'
//导入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
//导入组件
import HelloWorld from "./components/HelloWorld";
//创建全局组件
Vue.component(id:'hello-world', HelloWorld);
//在创建Vue实例之前,要将element-ui插入到Vue中 Vue.use(ElementUI); Vue.config.productionTip = false //创建实例 new Vue({ render: h => h(App),//render:渲染App根组件 }).$mount('#app')//app:index.html中的div且id=app的容器
使用全局组件时,只在需要的地方<id名称></id名称>
<template>
<div class="msg">
<!-- <span @click="username='路人'">有一天,{{username}}想去网吧上网</span>-->
<span @click="changeUsername">有一天,{{username}}想去网吧上网</span>
<p v-if="age >= 70">爷爷,你还是回去锻炼身体!</p>
<p v-else-if="age >= 18">欢迎光临,请愉快的上网吧</p>
<p v-else>{{username}}小朋友,作业写完了吗</p>
<hello-world></hello-world>
</div>
</template>
页面显示结果:
2、组件传值
父组件(App.vue)给子组件(HelloWorld.vue)传值:在子组件中使用prop
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: { //从父组件获取msg
msg: String,
title: Number,
}
}
</script>
父组件:在父组件中,传值既可以直接指定,也可以动态方式(data)进行
<!--template用于展示给用户,相当于MVVM中的V-->
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<!--在父组件中给子组件传值-->
<!-- <HelloWorld msg="欢迎来到柠檬班测试开发班级!"/>-->
<Greeting></Greeting>
<hello-world msg="这是一个msg" :title="title"></hello-world>
<!--第三步:在父组件中的template在使用-->
<!-- <ProjectList></ProjectList>-->
<!-- <ElementProject></ElementProject>-->
<!-- <Login></Login>-->
</div>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'//导入子组件
import Greeting from "./components/Greeting"; //第一步:导入子组件
// import ProjectList from "./components/ProjectList";
// import ElementProject from "./components/ElementProject";
// import Login from "./components/Login";
export default {
name: 'app', //定义组件名称
components: { //声明子组件
// HelloWorld,
Greeting, //第二步:声明子组件
// ProjectList,
// ElementProject
// Login
},
data(){
return{
title:'K帝帝'
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
页面效果:

3、slot插槽
略
二、路由
1、简介
- 创建单页面应用
- 官方路由组件,实现前端路由功能
对于单页面应用程序来说,主要通过url的hash(#)来实现不同页面的切换,同时hash还有一个特点HTTP请求中不会包含hash相关的内容,
所以单页面程序中的页面跳转主要用hash实现。
2、安装
npm install vue-router
3、简单路由
- 使用步骤
- 安装并导入vue-router(index.js文件中导入)
- 导入组件
- 创建路由
- 导出路由
- 在main.js中进行导入
- 根组件使用路由
//1.导入vue-router import Vue from 'vue' import VueRouter from 'vue-router' // 1. Use plugin. // This installs <router-view> and <router-link>, // and injects $router and $route to all router-enabled child components Vue.use(VueRouter) // 2.导入组件 import Greeting from "../components/Greeting"; import HelloWorld from "../components/HelloWorld"; import Login from "../components/Login"; import ProjectList from "../components/ProjectList"; import ElementProject from "../components/ElementProject"; // 3. Create the router(创建路由) const router = new VueRouter({ mode: 'history', base: __dirname, //routes数组中一个对象就是一条路由 routes: [ //在组件中可以用过this.$router.query { path: '/', component: HelloWorld }, { path: '/greeting', component: Greeting}, { path: '/login', component: Login}, { path: '/element', component: ElementProject}, { path: '/project', component: ProjectList}, ] }) //4. 导出路由 export default router;
path: 访问路径
component: 指定访问组件
main.js导入router
//导入vue.js import Vue from 'vue' //导入根组件 import App from './App.vue' //导入element-ui import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; //导入组件 import HelloWorld from "./components/HelloWorld"; import router from "./router/index" //创建全局组件 Vue.component('hello-world', HelloWorld); //在创建Vue实例之前,要将element-ui插入到Vue中 Vue.use(ElementUI); Vue.config.productionTip = false //创建实例 new Vue({ router, render: h => h(App),//render:渲染App根组件 }).$mount('#app')//app:index.html中的div且id=app的容器
根组件App.vue使用路由
//展示路由的页面内容 <router-view></router-view>
- 路由跳转
页面的地址切换,显示对应的页面,但是每次都需要手动输入地址,很不方便。
在根组件中增加router-link:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<ul>
<li><router-link to="/">主页</router-link> </li>
<li><router-link to="/Greeting">问候</router-link> </li>
<li><router-link to="/Login">登录</router-link> </li>
<li><router-link to="/Project">项目列表</router-link> </li>
<li><router-link to="/ElementProject">elementUI使用项目</router-link> </li>
</ul>
<!--展示路由的页面内容-->
<router-view></router-view>
</div>
</template>
刷新页面:当点击主页链接文字时,跳转到对应页面。

如果路由表路径更改了,那么根组件也要修改,这种情况下,可以给路由增加name属性。
index.js routes修改成:
// 3. Create the router(创建路由) const router = new VueRouter({ mode: 'history', base: __dirname, //routes数组中一个对象就是一条路由 routes: [ //在组件中可以用过this.$router.query { path: '/', component: HelloWorld, name:'home'}, { path: '/greeting', component: Greeting, name:'greeting'}, { path: '/login', component: Login, name:'login' }, { path: '/element', component: ElementProject, name:'element'}, { path: '/project', component: ProjectList, name:'project'}, ] })
根组件App.vue更新成:
<ul>
<li><router-link :to="{ame: 'home'}">主页</router-link> </li>
<li><router-link :to="{name: 'greeting'}">问候</router-link> </li>
<li><router-link :to="{name: 'login'}">登录</router-link> </li>
<li><router-link :to="{name: 'project'}">项目列表</router-link> </li>
<li><router-link :to="{name: 'element'}">elementUI使用项目</router-link> </li>
</ul>
-
路由参数类型
- 查询字符串参数
在组件中可以通过this.$route.query来获取查询字符串参数
<template>
<div class="msg">
<!-- <span @click="username='路人'">有一天,{{username}}想去网吧上网</span>-->
<span @click="changeUsername">有一天,{{username}}想去网吧上网</span>
<p v-if="age >= 70">爷爷,你还是回去锻炼身体!</p>
<p v-else-if="age >= 18">欢迎光临,请愉快的上网吧</p>
<p v-else>{{username}}小朋友,作业写完了吗</p>
</div>
</template>
<script>
export default {
name: "Greeting",
data(){
return {
username: '马仔',
age: 16
}
},
/* eslint-disable */
methods: {
changeUsername: function () {
//this就相当于python中的self
this.username = '一个没有整容需求的人'
},
created(){
console.log('实例创建之后,能获取到this');
console.log('username为:',this.username);
this.username = this.$route.query.username;
this.age = this.$route.query.age;
},
mounted(){
console.log('vue实例挂载到DOM树后')
}
}
}
</script>
<style scoped>
.msg p{
color: red;
}
</style>

2.路径参数
查询路径参数时使用this.$route.query.params获取

4、嵌套路由
在父路由下添加子路由
要在嵌套的出口中渲染组件,需要在 VueRouter 的参数中使用 children 配置:
//1.导入vue-router import Vue from 'vue' import VueRouter from 'vue-router' // 1. Use plugin. // This installs <router-view> and <router-link>, // and injects $router and $route to all router-enabled child components Vue.use(VueRouter) // 2.导入组件 import Greeting from "../components/Greeting"; import HelloWorld from "../components/HelloWorld"; import Login from "../components/Login"; import ProjectList from "../components/ProjectList"; import ElementProject from "../components/ElementProject"; // 3. Create the router(创建路由) const router = new VueRouter({ mode: 'history', base: __dirname, //routes数组中一个对象就是一条路由 routes: [ //在组件中可以用过this.$router.query { path: '/', component: HelloWorld, name:'home'}, { path: '/greeting:username', component: Greeting, name:'greeting'}, { path: '/element', component: ElementProject, name:'element'}, { path: '/project', component: ProjectList, name:'project', children:[ {path:'/login', component: Login}, ] }, { path: '/login', component: Login, name:'login' }, ] }) //4. 导出路由 export default router;
父路由增加渲染出口
<template>
<div>
<table>
<tr>
<th v-for="(project,key) in project_headers" v-bind:key="key">{{project}}</th>
</tr>
<tr v-for="(item, key) in projects" v-bind:key="key">
<td>{{item.name}}</td>
<td>{{item.leader}}</td>
<td>{{item.app_name}}</td>
</tr>
</table>
<p>=========================</p>
<router-view></router-view>
</div>
</template>
要注意,以 / 开头的嵌套路径会被当作根路径,从根路由开始查找;如果不加/,则自动拼接父路由当中,效果图:

三、axios
1、简介
非常流行的请求库
vue发起异步请求的标配
2、安装
npm install axios -S
3、案例
接口:https://dog.ceo/api/breeds/image/random
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image :src='url' :fit="cover"></el-image>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'HelloWorld',
props: { //从父组件获取msg
msg: String,
title: Number,
},
data(){
return {
url:''
}
},
mounted() {
axios.get('https://dog.ceo/api/breeds/image/random')
.then(function (response) {
console.log(response.data);
this.url=response.data.messages
//此时的this指的是当前函数
})
.catch(function (err) {
console.log(response.err)
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<!--视图样式定义-->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
效果图:

发现图片加载失败,改用箭头函数方式:
mounted() { //方式一:不推荐(不行) // axios.get('https://dog.ceo/api/breeds/image/random') // .then(function (response) { // console.log(response.data); // this.url=response.data.messages // //此时的this指的是当前函数 // // }) // .catch(function (err) { // console.log(response.err) // }); //方式二:定义成箭头函数 axios.get('https://dog.ceo/api/breeds/image/random') .then(response => { console.log(response.data); this.url=response.data.message //此时的this指的是当前函数 }) .catch(function (err) { console.log(err) }); }
效果图:

在项目中,有很多的请求,为了方便管理,将api抽离出来放置在指定的文件中: api/api.js
axios发送get请求,封装成函数如下:
import axios from 'axios' axios.get('https://dog.ceo/api/breeds/image/random') function () { //匿名函数 return axios.get('https://dog.ceo/api/breeds/image/random') } () => { //箭头函数 return axios.get('https://dog.ceo/api/breeds/image/random') } export const dogs=() => { //最佳写法 return axios.get('https://dog.ceo/api/breeds/image/random') }
当域名更新时,每次各处涉及到的域名更改太麻烦,将域名作为变量抽离出来
var host='https://dog.ceo'; export const dogs=() => { //最佳写法 return axios.get(url: `${host}/api/breeds/image/random`) //在字符串中解析变量,需要增加反引号 };
在HelloWorld.vue中使用api.js,需要导入
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
</div>
</template>
<script>
// import axios from 'axios'
import {dogs} from'../api/api.js'
export default {
name: 'HelloWorld',
props: { //从父组件获取msg
msg: String,
title: Number,
},
data(){
return {
url:'',
}
},
mounted() {
//方式一:不推荐(不行)
// axios.get('https://dog.ceo/api/breeds/image/random')
// .then(function (response) {
// console.log(response.data);
// this.url=response.data.messages
// //此时的this指的是当前函数
//
// })
// .catch(function (err) {
// console.log(response.err)
// });
//方式二:定义成箭头函数
dogs()
.then(response => {
console.log(response.data);
this.url=response.data.message
//此时的this指的是当前函数
})
.catch(function (err) {
console.log(err)
});
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<!--视图样式定义-->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
四、插槽
默认情况下,在调用的子组件的开标签和闭标签之间添加的内容会忽略。若不想忽略,则要在调用的子组件加上slot插槽。
1、插槽方式
greerting.vue调用hello-world子组件,在hello-world子组件加上插槽。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
<slot></slot>
</div>
</template>
<template>
<div class="msg">
<!-- <span @click="username='路人'">有一天,{{username}}想去网吧上网</span>-->
<span @click="changeUsername">有一天,{{username}}想去网吧上网</span>
<p v-if="age >= 70">爷爷,你还是回去锻炼身体!</p>
<p v-else-if="age >= 18">欢迎光临,请愉快的上网吧</p>
<p v-else>{{username}}小朋友,作业写完了吗</p>
<hello-world>
<p>插入到子组件之间的内容</p>
</hello-world>
</div>
</template>
<script>
export default {
name: "Greeting",
data(){
return {
username: '马仔',
age: 17,
}
},
/* eslint-disable */
methods: {
changeUsername: function () {
//this就相当于python中的self
this.username = '一个没有整容需求的人'
},
//created没有生效
created(){
console.log('实例创建之后,能获取到this');
console.log('username为:',this.username);
this.username = this.$route.query.username;
this.age = this.$route.query.age;
},
mounted(){
console.log('vue实例挂载到DOM树后')
}
}
}
</script>
<style scoped>
.msg p{
color: red;
}
</style>
效果图:

也可以在插槽标签之间添加内容,但是如果调用的子组件标签之间有内容的话,会覆盖插槽标签之间的内容。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
<slot>
<p>我们一起学猫叫</p>
</slot>
</div>
</template>
效果图依然是上图,将调用子组件标签之间的内容注释后,效果如下:

在子组件中,有多个命名插槽,在vue不同版本中,有两种做法:
如在hello-world子组件中,有3个插槽,其中1个默认插槽,两个命名插槽,在使用子组件插槽时,vue2.6前后版本做法如下:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
<slot>
<p>我们一起学猫叫</p>
</slot>
<slot name="part1"></slot>
<slot name="part2"></slot>
<slot name="part3"></slot>
</div> </template>
<template>
<div class="msg">
<!-- <span @click="username='路人'">有一天,{{username}}想去网吧上网</span>-->
<span @click="changeUsername">有一天,{{username}}想去网吧上网</span>
<p v-if="age >= 70">爷爷,你还是回去锻炼身体!</p>
<p v-else-if="age >= 18">欢迎光临,请愉快的上网吧</p>
<p v-else>{{username}}小朋友,作业写完了吗</p>
<hello-world>
<!-- <p>插入到子组件之间的内容</p>-->
<!--在vue2.6之前版本-->
<p slot="part1">一起喵喵喵</p>
<!--在vue2.6之后版本-->
<template v-slot:part2>
在你面前撒个娇
</template>
<template #part3>
哎哟喵喵喵喵
</template>
</hello-world>
</div>
</template>
效果图:

2、插槽作用域
在插槽part4中,绑定属性user,属性名username
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
<slot>
<p>我们一起学猫叫</p>
</slot>
<slot name="part1"></slot>
<slot name="part2"></slot>
<slot name="part3"></slot>
<!--插槽作用域-->
<slot name="part4" :user="username"></slot>
<slot name="part5" user="icon"></slot>
</div> </template>
如何获取插槽part4中username的值呢?
在vue2.6版本之前:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>开班事项</p>
<h3>禁开车,只除草</h3>
<h3>禁灌水,只下地</h3>
<h3>禁大鱼,只学习</h3>
<h3>{{title}}</h3>
<el-image
style="width: 100px; height: 100px"
:src="url"
:fit="cover">
</el-image>
<slot>
<p>我们一起学猫叫</p>
</slot>
<slot name="part1"></slot>
<slot name="part2"></slot>
<slot name="part3"></slot>
<!--插槽作用域-->
<slot name="part4" :user="username"></slot>
<slot name="part5" user="icon"></slot>
<slot name="part6" user="黏黏"></slot>
</div>
</template>
在vue2.6版本之后:
<template>
<div class="msg">
<!-- <span @click="username='路人'">有一天,{{username}}想去网吧上网</span>-->
<span @click="changeUsername">有一天,{{username}}想去网吧上网</span>
<p v-if="age >= 70">爷爷,你还是回去锻炼身体!</p>
<p v-else-if="age >= 18">欢迎光临,请愉快的上网吧</p>
<p v-else>{{username}}小朋友,作业写完了吗</p>
<hello-world>
<!-- <p>插入到子组件之间的内容</p>-->
<!--在vue2.6之前版本-->
<p slot="part1">一起喵喵喵</p>
<!--在vue2.6之后版本-->
<template v-slot:part2>
在你面前撒个娇
</template>
<template #part3>
哎哟喵喵喵喵
</template>
<!--插槽作用域-vue2.6之前版本-->
<p slot='part4' slot-scope="scope">
{{scope.user}}一起喵喵喵喵
</p>
<!--插槽作用域-vue2.6之后版本-->
<template #part5="scope">
{{scope.user}}我的心脏砰砰跳
</template>
<!--或者以下的方式-->
<template #part6="{user}">
<p>{{user}}我的心脏砰砰跳</p>
</template>
</hello-world>
</div>
</template>
效果图:


浙公网安备 33010602011771号