【Vue.js】Vue 2.X学习篇二

前言

前面已经对基础的vue知识有个简单的解说,接下来就是进阶的任务,学习Vue Cli脚手架和应用。

一、Vue Cli 脚手架

1、使用Vue Cli 的原因

  • 在项目当中,我们应该使用的是Vue Cli 脚手架,因为我那可以使用一些跟新更主流的方法。
  • 可使用ES6语法。Vue Cli其实就是通过Webpack来搭建开发环境。开发环境当中已经加载了项目中应用的内容,作为开发人员,我们不需要考虑是否要使用ES6语法,因为我们不必要担心浏览器的兼容,在脚手架里通过Loader将ES6打包成ES5,在浏览器可以正常运行,
  • 项目是在环境编译,而不是在浏览器编译,因此速度会很快。 当我们编译后浏览器会自动的刷新,方便我们查看。

2、搭建脚手架

Vue Cli脚手架是依赖于Node.js的,因此我们首先需要安装Node环境,具体安装步骤

安装Vue
最新稳定版

$ npm install vue

查看版本

$ vue --version

下载模板,项目初始化。
进入要存放项目的目录,输入以下命令

$ vue init webpack vue-app

结构为

$ vue init webpack 项目名称

安装成功之后,将会提醒你进行下一步的操作。

3、vue-cli目录解析:

  • build 文件夹:构建了客户端和服务端的,用于存放 webpack相关配置和脚本。实际的开发中一般不更改它的配置,webpack.base.conf.js 用于配置less、sass等css预编译库,或者配置一下 UI 库。
  • config 文件夹:主要存放配置文件,用于区分开发环境、线上环境的不同。常用到此文件夹下 config.js 配置开发环境的 端口号、是否开启热加载 或者设置生产环境的静态资源相对路径、是否开启gzip压缩、npm run build 命令打包生成静态资源的名称和路径等。
  • dist文件夹:默认 npm run build 命令打包生成的静态资源文件,用于生产部署。
  • node_modules:存放npm命令下载的开发环境和生产环境的依赖包。
  • static 放静态文件。
  • index.html:设置项目的一些meta头信息和提供<div id="app"></div>用于挂载 vue 节点。
  • package.json:用于 node_modules资源部 和 启动、打包项目的 npm 命令管理。

重点文件 src

  • src: 存放项目源码及需要引用的资源文件。
  • src下assets:存放项目中需要用到的资源文件,css、js、images等。
  • src下componets:存放vue开发中一些公共组件:header.vue、footer.vue等。
  • src下emit:自己配置的vue集中式事件管理机制。
  • src下routervue-router vue路由的配置文件。
  • src下service:自己配置的vue请求后台接口方法。
  • src下page:存在vue页面组件的文件夹。
  • src下util:存放vue开发过程中一些公共的.js方法。
  • src下vuex:存放 vuex 为vue专门开发的状态管理器。
  • src下app.vue:根组件,使用标签<route-view></router-view>渲染整个工程的.vue组件。
  • src下main.js:vue-cli工程的入口文件。与index.html文件直接相连的文件。

组件App.vue介绍
App.vue其实是一个公共的组件,里面包含三个部分,分别是:

  • 1模板:编写html的结构(注意,模板里面只有一个跟标签)
  • 2行为:处理一些业务逻辑,处理数据。
  • 3样式:解决页面的样式

执行流程
index.html会执行main.js,而main.js会实例化Vue对象,接下来就会执行App.vue的组件,如果模板有内容,就会往index.html的容器里插入相应的内容。

4、项目初始化

组件化开发,是Vue项目中常见的应用。
我们可以将页面分割成若干份,然后每一份都可右一个或多个组件组成。
在这里插入图片描述
在安装完毕之后我们就可以通过npm run dev将项目打开
在这里插入图片描述
这里都是组件(components)下HelloWorld.vue的内容,我们将vue文件的模板、行为、样式都删除,留下主要的部分。

App.vue

<template>
  <div id="app">
  </div>
</template>

<script>
export default {
     
     
  name: 'App'
}
</script>

<style>

</style>

HelloWord.vue

<template>
  <div class="hello">
  </div>
</template>

<script>
export default {
     
     
  name: 'HelloWorld',
  data () {
     
     
    return {
     
     
      
    }
  }
}
</script>

<style scoped>

</style>

二、项目开发相关

1、组件嵌套

components下创建一个新的文件Test.vue,写入我们的测试数据

<template>
    <div class="test">
        {
   
   {title}}
    </div>
</template>

<script>
export default {
     
     
  name: 'test',
  data () {
     
     
    return {
     
     
      title: "大家好!"
    }
  }
}
</script>

<style scoped>
</style>

全局注册组件

在main.js内引入Test.vue,这样就可以在App.vue中使用Test的内容
main.js

import Test from "./components/Test"

//全局注册组件
Vue.component("test",Test);

App.vue

<template>
  <div id="app">
    <test></test>
  </div>
</template>

局部注册组件

在App.vue中直接引入Test.vue即可使用
App.vue

<template>
  <div id="app">
    <test></test>
  </div>
</template>
<script>
//局部注册组件
import Test from './components/Test'
export default {
     
     
  name: 'App',
  data() {
     
     
    return {
     
     
      title: "这是App的内容"
    }
  },
  components:{
     
     
    "test" : Test
  }
}
</script>

<style>
</style>

2、scoped样式域

如果我们在全局的App.vue下为我们的网页定义样式,按照传统的style样式的话,它就会应用到我们的整个网页当中,包括子组件。那有时候我们想让子组件不收全局样式的影响,我们就可以使用scoped样式域,它会形成一个[data-v-xxxx]的标识,不同元素设置了标识就会往style中相应的域中去匹配样式。

App.vue,这里将App.vue的h1样式中color设置成bluespan颜色为绿色,同时使用scoped样式域

<template>
  <div id="app">
    <h1>这是App的H1</h1>
    <span>这里是App的span内容</span>
    <test></test>
  </div>
</template>

<script>
//局部注册组件
import Test from './components/Test'
export default {
     
     
  name: 'App',
  data() {
     
         
return {
     
     
    }
  },
  components:{
     
     
    "test" : Test
  }
}
</script>

<style scoped>
h1{
     
     
  color: blue;
}
span{
     
     
  color: green;
}
</style>

Test.vue样式的h1样式中color设置成pinkspan颜色为默认黑色,同时也使用scoped样式域。

<template>
    <div class="test">
        <h1>这是Test的H1</h1>
        <span>{
   
   {title}}</span>
    </div>
</template>

<script>
export default {
     
     
  name: 'test',
  data () {
     
     
    return {
     
     
      title: "这里是Test的span内容"
    }
  }
}
</script>
<style scoped>
h1{
     
     
    color:pink;
}
</style>

这时候就会得到以下的效果
在这里插入图片描述
我们可以看到Test中的span样式并没有被App.vue中的样式应用,两者的h1标签样式也是分别得到了不同的效果。
在这里插入图片描述
在这里插入图片描述

3、一个简单的网页demo

Header.vue

<template>
    <header>
        <p>{
   
   {title}}</p>
    </header>
</template>

<script>
export default {
     
     
  name: 'app-header',
  data () {
     
     
    return {
     
     
      title: "这里是header的内容"
    }
  }
}
</script>

<style scoped>
header{
     
     
    padding: 10px;
    background: lightpink;
}
p{
     
     
    color: lightslategray;
    text-align: center;
}
</style>

Main.vue

<template>
    <div class="main">
        <h1>Hello Everbody</h1>
        <ul>
            <li v-for="person in person" v-on:click="person.show = !person.show">
                <h2>{
   
   {person.name}}</h2>
                <h3 v-show="person.show">{
   
   {person.age}}</h3>
            </li>
        </ul>
    </div>
</template>

<script>
export default {
     
     
  name: 'app-main',
  data () {
     
     
    return {
     
     
      person: [
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
            {
     
     name: "Jack", age: 21, show: false},
        ]
    }
  }
}
</script>

<style scoped>
    .main{
     
     
        width: 100%;
        max-width: 1200px;
        margin: 40px auto;
        padding: 0 20px;
        box-sizing: border-box;
    }
    ul{
     
     
        display: flex;
        flex-wrap: wrap;
        list-style-type: none;
        padding: 0;
    }
    li{
     
     
        flex-grow: 1;
        flex-basis: 200px;
        text-align: center;
        padding: 30px;
        border: 1px solid #333;
        margin: 10px;
    }
</style>

Footer.vue

<template>
    <footer>
        <p>{
   
   {copyright}}</p>
    </footer>
</template>

<script>
export default {
     
     
  name: 'app-footer',
  data () {
     
     
    return {
     
     
        copyright: "copyright 2019.11"
    }
  }
}
</script>

<style scoped>
footer{
     
     
    padding: 6px;
    background: lightslategray;
}
p{
     
     
    color:lightpink;
    text-align: center;
}
</style>

App.vue

<template>
  <div id="app">
    <app-header></app-header>
    <app-main></app-main>
    <app-footer></app-footer>
  </div>
</template>

<script>
//局部注册组件
import Header from './components/Header'
import Main from './components/Main'
import Footer from './components/Footer'

export default {
     
     
  name: 'App',
  data() {
     
     
return {
     
     

    }
  },
  components:{
     
     
    "app-header": Header,
    "app-main": Main,
    "app-footer": Footer
  }
}
</script>

<style scoped>
h1{
     
     
  color: blue;
}
span{
     
     
  color: green;
}
</style>

其中Main.vue 下的样式解析

.main {
    
    
            width: 100%; /* 主体容器的宽度为100% */
            max-width: 1200px;/* 最大宽度为1200px */
            margin: 40px auto;/* 外边距上下40px,左右auto */
            padding: 0 20px;/* 内边距上下为0,左右20px */
            box-sizing: border-box;/* box-sizing就不用计算padding */
        }

        ul {
    
    
            display: flex;/* li在一行显示 */
            flex-wrap: wrap;/* 让内容不超出main容器 */
            list-style-type: none;/* 设置li的标记样式为无标记 */
            padding: 0;/* 取消父元素的padding值 */
        }

        li {
    
    
            flex-grow: 1;/* 如果一行只有一个,就会撑满整行,如果是有两个就两个撑满整行 */
            flex-basis: 200px;/* 设置弹性盒元素的伸缩长度为200px */
            text-align: center;/* 内容居中,可不用自定义 */
            padding: 30px;/* 内边距30px */
            border: 1px solid #333;/* 设置边框样式 */
            margin: 10px;/* 外边距都是10px */
        }

最终效果
在这里插入图片描述
在这里插入图片描述

4、Vue属性传值Props(父传子)

在上一个demo里我们将Main.vue里面的person数据放到App.vue的数据。

  • v-bind:person="person"(在调用子组件的时候,使用自定义绑定的属性,这样就绑定了一个person的值,相当于向子组件传入person的数据。)
  • props:["person"](在子组件接受父组件传过来的值,这样就可以使用了,与上面实现的效果相同)

App.vue

<template>
  <div id="app">
    <app-header></app-header>
    <app-main v-bind:person="person"></app-main>
    <app-footer></app-footer>
  </div>
</template>

<script>
//局部注册组件
import Header from "./components/Header";
import Main from "./components/Main";
import Footer from "./components/Footer";

export default {
     
     
  name: "App",
  data() {
     
     
    return {
     
     
      person: [
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false },
        {
     
      name: "Jack", age: 21, show: false }
      ]
    };
  },
  components: {
     
     
    "app-header": Header,
    "app-main": Main,
    "app-footer": Footer
  }
};
</script>
<style scoped>
h1 {
     
     
  color: blue;
}
span {
     
     
  color: green;
}
</style>

Main.vueprops里面可以接受多个值,里面规范了数据的类型,只有传入的值符合类型,才允许使用该数据。

export default {
    
    
  name: "app-main",
  props: {
    
    
    person: {
    
    
      type: Array,
      required: true
    }
  },
  data() {
    
    
    return {
    
    };
  }
};

5、理解传值和传引用

上述我们谈到父组件为子组件传值,子组件在接受参数的时候规定了数据的类型,JS中有基本类型值和引用类型值两种。

  • JavaScript 变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自以下 5 种基本数据类型:UndefinedNullBooleanNumberString
  • 引用类型:对象(Object)、数组(Array)、函数(Function)。引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。当复制保存着对象的某个变量时,操作的是对象的引用。但在为对象添加属性时,操作的是实际的对象。

因此如果上述的父组件对多个子组件都传递了person属性,而且接收的Array是属于引用类型,我们在一个地方改变的时候,所有的地方都会改变。

(1)传引用

App.vue

<app-main v-bind:person="person"></app-main>
<app-main v-bind:person="person"></app-main>

Main.vue

<button v-on:click="deletePerson">删除</button>
methods: {
    
    
    deletePerson: function(){
    
    
      this.person.pop();
    }
}

这时候上面和下面的两部分都会执行deletePerson这个方法
在这里插入图片描述

(2)传值

当我们传入一个Number类型的时候
App.vue

<app-header v-bind:age="age"></app-header>
<app-footer v-bind:age="age"></app-footer>
data() {
    
    
    return {
    
    
      age: 21
    };
}

在Header.vue和Footer.vue分别都接收了这个值

<p>
  {
   
   {title}}
  <span v-on:click="changeAge">{
   
   {age}}</span>
</p>

在这里插入图片描述
并对Header中21添加一个点击事件,当点击21时,将age修改为22

export default {
    
    
  name: 'app-header',
  props: {
    
    
    age:{
    
    
      type: Number
    }
  },
  data () {
    
    
    return {
    
    
      title: "这里是header的内容"
    }
  },
  methods: {
    
    
    changeAge: function(){
    
    
      this.age = 22;
    }
  }
}

可见header和footer的Number类型的数据不受影响
在这里插入图片描述
但是这里会有一个报错的信息
在这里插入图片描述
意思是子组件修改父组件的值导致报错,我们应该在这里避免直接修改父组件的值。
解决方案就是在data里重命名接收的值,比如命名为appAge,在该页面中就可以使用AppAge这个值了。

<template>
    <header>
        <p>
          {
   
   {title}}
          <span v-on:click="changeAge">{
   
   {appAge}}</span>
        </p>
    </header>
</template>

<script>
export default {
     
     
  name: 'app-header',
  props: {
     
     
    age:{
     
     
      type: Number
    }
  },
  data () {
     
     
    return {
     
     
      title: "这里是header的内容",
      appAge: this.age
    }
  },
  methods: {
     
     
    changeAge: function(){
     
     
      this.appAge= 22;
    }
  }
}
</script>

6、事件传值(子组件传父组件)

我们在点击子组件时,可以向父组件传递事件,子组件通过this.$emit() 注册事件,父组件通过v-on:来接收事件,并且可重新命名后对该事件进行相应的操作。
Header.vue

<template>
    <header>
        <p v-on:click="changeAge">
          {
   
   {title}}
        </p>
    </header>
</template>
export default {
    
    
  name: 'app-header',
  data () {
    
    
    return {
    
    
      title: "这里是header的内容"
    }
  },
  methods: {
    
    
    changeAge: function(){
    
    
      this.$emit("changeAge", 22);
    }
  }
}

App.vue

<p>{
   
   {title}}{
   
   {age}}</p>
<app-header v-on:changeAge="changeAge($event)"></app-header>
export default {
    
    
  name: "App",
  data() {
    
    
    return {
    
    
      title: "这里是App.vue 的age:",
      age: 21
    };
  },
  methods: {
    
    
    changeAge(newAge){
    
    
      this.age = newAge;
    }
  },
  components: {
    
    
    "app-header": Header,
    "app-main": Main,
    "app-footer": Footer
  }
};

7、Vue的生命周期

  • New Vue 是实例Vue的对象,没有创建vue实例之前,就会有beforeCreate这个方法,可是实行加载的操作;
  • 当进入到created当中可以获取一些数据,可以获取结构的一些数据,比如请求网络的接口,把请求的数据赋给属性。后续就可以展示dom,这时候加载就要结束,开始去渲染DOM。
  • 当执行完created执行完毕后,页面还没被展示出来,继续往下走,判断main.js当中是否有el?如果有就会检查template选项是否存在,如果没有就会检查$mount(el) ,
    new Vue({
          
          
       	el:’#app’,
       	template:<App/>,
       	components: {
          
           App }
    }).$mount(el)
    
    都没有生命周期就会结束。接下来再判断template是组件<App/>还是html标签内容,有的话就往下执行,如果都没有生命周期也已经结束了,因为没有可以渲染的东西。
  • 进入到下一个钩子函数befoedMount,mount就是挂载,现在就是开始编译当前的模板,就是template的内容,其实是在虚拟DOM中执行,执行完毕后,开始将element指向的元素往模板放置。
  • 进入到mounted,已经编译完毕,开始挂载,一旦结束,页面展示。如果想在页面显示出来之前进行操作,就在该阶段进行。

Vue官方文档中的Vue生命周期图示。
在这里插入图片描述

下面通过一组提示可以很清楚的知道Vue的生命周期。

beforeCreate: function() {
    
    
  alert(
    "组件实例化之前执行的函数,这时候的data和methods中的数据还没有初始化,所以是不可以在这个阶段使用data中的数据以及methods中的方法"
  );
},
created: function() {
    
    
  alert("组件实例化完毕,但是页面还未显示,data和methods都已经被初始化了,如果想调用methods中的方法或者操作data中的数据,最早是可以在这个阶段操作");
},
beforeMount: function() {
    
    
  alert("组件挂载前,页面仍然为展示,但是内存中已经编译好了模板,也就是说虚拟DOM已经配置好了");
},
mounted: function() {
    
    
  alert("组件挂载完毕,如果想要向DOM中插入节点,最早可以在这个阶段进行,此方法执行后,页面展示");
},
beforeUpdate: function() {
    
    
  alert("组件更新前,页面内的内容仍然没有更新,但是虚拟DOM已经配置好");
},
updated: function() {
    
    
  alert("组件更新完毕,所有数据都已经保持同步了,此方法执行后,页面新内容显示");
},
beforeDestory: function() {
    
    
  alert("组件销毁前,这个时候所有的data和methods以及其他内容都是可用的,还没有真正被销毁");
},
destoryed: function() {
    
    
  alert("组件销毁,所有的data和methods以及其他内容都是不可用的");
}

8、vue路由与请求

往期我们是通过a标签进行页面的跳转,a标签有一个属性叫做href,对应传入地址或者是路径时,a标签每次点击的时候对发生网络请求,页面都会刷新。
而路由其实与a标签实现的效果是相同的,但是路由的性能优化的比较好,使用了路由机制,无论点击多少,他都不会请求和刷新页面,直接进入需要进入的地址。

安装路由
npm install vue-router --save-dev

cnpm install vue-router --save-dev

main.js引入路由

import Vue from 'vue'
import VueRouter from 'vue-router' //引入路由
import App from './App'
import HelloWorld from './components/HelloWorld'; //引入HelloWorld.vue,一个跳转页面
import Home from './components/Home';//引入Home.vue,后面创建一个新主页,由这个页面跳转到HelloWorld页面

Vue.config.productionTip = false
Vue.use(VueRouter) //使用路由
// 配置路由
const router = new VueRouter({
    
    
  routes: [
    {
    
    path: "/", component: Home},
    {
    
    path: "helloworld", component: HelloWorld}
  ]
})

new Vue({
    
    
  router, //添加路由
  el: '#app',
  components: {
    
     App },
  template: '<App/>'
})

App.vue中使用路由标签

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

HelloWorld.vue
<template>
  <div class="hello">
    Hello World
  </div>
</template>

<script>
export default {
     
     
  name: 'HelloWorld',
  data () {
     
     
return {
     
     

    }
  }
}
</script>
<style scoped>

</style>

这时候我们观察页面的地址带个#号,将之去掉就在main.js配置路由的地方使用mode: "history"

// 配置路由
const router = new VueRouter({
    
    
  routes: [
    {
    
    path: "/", component: Home},
    {
    
    path: "helloworld", component: HelloWorld}
  ],
  mode: "history"
})

9、fetch请求

mounted钩子函数中请求接口数据

mounted(){
    
    
    const posts = fetch("http://jsonplaceholder.typicode.com/posts").then(res => {
    
    
      return res.json();
    })
    .then(postos => {
    
    
      console.log(postos);
    })
  }

提交表单数据

<template>
  <div id="window">
        <div class="center">
          <form @submit.prevent="onSubmit">
            <input type="text" v-model="post.title" />
            <input type="checkbox" v-model="post.id"/>
            <input type="submit" value="提交"/>
          </form>

          <ul>
            <li v-for="post in posts">
              <h1>{
   
   {post.title}}</h1>
              <p>{
   
   {post.id}}</p>
            </li>
          </ul>
        </div>
  </div>
</template>

<script>
export default {
     
     
  name: 'HomeWindow',
  data() {
     
     
    return {
     
     
      posts: [],
      post: {
     
     
        id: null,
        title: ""
      }
    }
  },
  mounted(){
     
     
    const posts = fetch("http://jsonplaceholder.typicode.com/posts").then(res => {
     
     
      // console.log(res);
      return res.json();
    })
    .then(posts => {
     
     
      this.posts = posts;
    })
  },
  methods: {
     
     
    onSubmit(){
     
     
      fetch("http://jsonplaceholder.typicode.com/posts",{
     
     
        method: "POST",
        body: JSON.stringify(this.post),
        headers: {
     
     
          "Content-type": "application/json"
        }
      }).then(res =>{
     
     
        return res.json();
      }).then(posts => {
     
     
        this.posts.unshift(posts);
      })
    }
  }
}
</script>

10、Axios请求

安装axios

npm install axios

重新启动可能会有以下问题
在这里插入图片描述
出现了以下的错误Refused to load the image ‘http://localhost:8080/favicon.ico’ because it vio…
在这里插入图片描述
解决办法:Refused to load the image ‘http://localhost:8080/favicon.ico’

使用axios

在相应的文件中script引入axios
import axios from 'axios'

get方法

axios.get("http://jsonplaceholder.typicode.com/posts").then(res => {
    
    
    console.log(res.data);
})

post方法

axios.post("http://jsonplaceholder.typicode.com/posts",this.post).then(res => {
    
    
    console.log(res.data);
})

相比fetch来说axios请求是比较优化简洁的。

11、动态组件与数据缓存

动态组件实现的效果就是在页面进行微小切换的时候,比如div1和div2的内容进行切换。

定义两个不同内容的组件,在home中引入他们

<template>
  <div id="div1">
    这是Div1 的内容
    <input type="text"/>
  </div>
</template>

<script>
export default {
     
     
  name: 'Div1'
}
</script>
<style scoped>
    input{
     
     
        border: 1px #000 solid;
    }
</style>
<template>
  <div id="div2">
    这是Div2 的内容
    <input type="text"/>
  </div>
</template>

<script>
export default {
     
     
  name: 'Div2'
}
</script>
<style scoped>
    input{
     
     
        border: 1px #000 solid;
    }
</style>

Home.vue引入Div1和Div2,通过:is来绑定组件,按钮点击后切换两个组件,从而实现动态组件。

<template>
  <div id="home">
    <component :is="component"></component>
    <button @click="component = 'Div1'">Div1</button>
    <button @click="component = 'Div2'">Div2</button>
  </div>
</template>

<script>
import Div1 from './components/Div1'
import Div2 from './components/Div2'
export default {
     
     
  name: 'Home',
  components: {
     
     
    Div1,
    Div2
  },
  data(){
     
     
    return {
     
     
      component: "Div1"
    }
  }
}
</script>
<style>
</style>

在这里插入图片描述
但是我们发现,如果向Div2输入框中输入内容,再切换到Div1的话,这时候回去看Div2的输入框,内容已经不在了。
在这里插入图片描述
在这里插入图片描述
也就是说,每一次切换的时候,都会触发依次请求,请求变得很频繁,重新获取组件,这样就会消耗很大的资源。这时候就需要使用缓存.

keep-alive缓存

将组件包裹起来,组件就会实现缓存

<keep-alive>
  <component :is="component"></component>
</keep-alive>

12、slot插槽

slot插槽可以理解为一个占位,在父组件引用子组件时,使用一个子组件标签,这时候如果没有使用插槽,往子组件标签内写入标签是不能展示出来的。

<template>
  <div id="homediv">
    这是Div 的内容
    <input type="text"/>
  </div>
</template>

<script>
export default {
     
     
  name: 'HomeDiv'
}
</script>
<style scoped>
    input{
     
     
        border: 1px #000 solid;
    }
</style>
<template>
  <div id="home">
    <home-div>
      <span>这里是home插入的标签</span> <!-- 不被显示 -->
    </home-div>
  </div>
</template>

<script>
import HomeDiv from './components/HomeDiv'
export default {
     
     
  name: 'Home',
  components: {
     
     
    HomeDiv
  }
}
</script>
<style>
</style>

在这里插入图片描述

在子组件中添加插槽,内容就可以通过插槽进行插入(位置可自定义,前或后)

<div id="homediv">
    这是Div 的内容
    <input type="text"/><br>
    <slot></slot>
</div>

在这里插入图片描述

使用单纯的插槽占位,只会将父组件传入的所有html内容往里塞,定义多个就塞多次。
在这里插入图片描述
所以说如果需要适用更复杂的操作的话,就需要给各自一个标识,添加slot属性,以及name标识

<home-div>
  <span slot="span1">这里是home插入的span1</span>
  <span slot="span2">这里是home插入的span2</span>
</home-div>
<template>
  <div id="homediv">
    <slot name="span1"></slot><br>
    这是Div 的内容
    <input type="text"/><br>
    <slot name="span2"></slot>
  </div>
</template>

在这里插入图片描述

样式域和属性定义区别

  • 在上述使用slot时,定义样式可以在子组件写,也可在父组件写。

  • 而属性定义不同
    数据在哪传入,就在哪里定义,我们在父组件Home中向子组件HomeDiv传入一个title属性,必须在父组件中定义title这个属性值,不然就会找不到title这个属性。而在HomeDiv总定义title是属于子组件中的属性,不属于父组件中的属性。
    也就是说标签在哪,属性就需要在哪里定义。

总结

重在积累,加油!

猜你喜欢

转载自blog.csdn.net/weixin_42339197/article/details/103015879