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、简单路由

  • 使用步骤
  1. 安装并导入vue-router(index.js文件中导入)
  2. 导入组件
  3. 创建路由
  4. 导出路由
  5. 在main.js中进行导入
  6. 根组件使用路由
//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>
  • 路由参数类型

  1. 查询字符串参数

在组件中可以通过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>

效果图:

 

 

 

posted @ 2019-10-07 17:28  sinder2018  阅读(31)  评论(0)    收藏  举报