Vue学习笔记——麻麻再也不用担心我的Vue!

Vue学习笔记——步步高点读机,麻麻再也而不用担心我的Vue!

这是一个学习笔记,基于b站蔡蔡小趴菜的vue教学视频做的

注:CSDN会对段落内的html标签屏蔽,所以本文非代码块的html标签以缺半的形式展示

文章目录

    • Vue学习笔记——步步高点读机,麻麻再也而不用担心我的Vue!
      • Vue应用结构
      • 模板语法、属性绑定、条件渲染、列表渲染 忘记笔记了,反正很简单,跳过(
      • 事件处理
        • 内联事件处理器
        • 方法事件处理器
        • 事件传参
      • 事件修饰符
      • 数组变化侦测
      • 计算属性
      • Class绑定
      • Style绑定
      • 侦听器
      • 表单输入绑定
      • 模板引用(DOM引用)
      • 组件
        • 组件组成
        • 组件嵌套关系
        • 组件的注册方式 ( 引入方式 )
        • 组件传递数据_Props
        • 组件传递Props校验 (对类型的校验、默认值和必选项的校验)
        • 组件事件 (可以实现子传父)
        • 组件事件配合v-model
        • 组件Props子传父 (函数方法)
        • 透传Atrribute
        • 插槽
          • 插槽基础
          • 插槽作用域
          • 插槽默认内容
          • 具名插槽
          • 插槽数据子传父
          • 插槽数据子传父(具名情况下)
        • 组件的生命周期
        • 生命周期的应用
        • 动态组件
        • 组件保持存活
        • 异步组件
      • 依赖注入
      • 路由
        • 路由基础
        • 带参路由
        • 嵌套路由

Vue应用结构

Vue大致结构如下:

Vue学习笔记——麻麻再也不用担心我的Vue!_第1张图片

  • **package-lock.json: ** 在使用 npm 安装包时自动生成的一个文件,它用于锁定当前项目的包的版本,以确保在不同的环境中安装的 包的版本一致

  • package.json: 项目的配置文件,包含了项目的依赖、脚本命令、版本号等信息。

  • README.MD: 说明

  • vite.config.js: Vite 构建工具的配置文件,它用于配置和定制 Vite 项目的构建行为和开发环境

  • public文件夹: 存放不需要经过Webpack处理的静态资源文件。这些文件会直接复制到构建目录中,并可以在HTML文件中

  • src文件夹: 源代码

  • assets文件夹: 用于存放应用需要的静态资源文件,如图片、字体、样式等。这些文件可以在组件中通过相对路径引用 (与public区别是会经过Webpack处理,如果部署在服务器上的话就把静态资源放在这里)

  • components文件夹: 存放vue组件

  • App.vue: vue的根组件

  • index.html: 这个文件里面是最基本的html页面代码,body中有

    作为引入vue组件的入口

  • main.js:

    import { createApp } from 'vue'  //引入创建vue实例的方法
    import App from './App.vue       // App就是根组件
    
    const app = createApp(App); // 创建 Vue 应用实例——基于根组件创建
    app.mount('#app'); // 将应用挂载到 id 为 "app" 的 DOM 元素上(也就是index.html的入口)
    
  • view文件夹: 存放vue的页面文件,基于路由进行页面跳转

  • router文件夹: 路由文件夹

  • index.js: 路由配置文件,包括路由页面和对应路径

模板语法、属性绑定、条件渲染、列表渲染 忘记笔记了,反正很简单,跳过(

事件处理

事件处理分为内联事件处理器方法事件处理器

事件通过 @click = "handler " 或者 v-on:click="methodName"触发

内联事件处理器

handler处是一段简单的Js代码,为一个可以返回值的表达式

<template>
    <h3>内联处理</h3>
    <button @click="count++">Add</button>
    <p>{{ count }}</p>
</template>


<script>
  export default {
    data() {
      return{
        count:0
      }

    }

  }

</script>
方法事件处理器

和内联事件处理不同,handler是一个方法名,调用methods:{}内的方法

PS:this.可以全局调用data(){}内的变量

<template>
    <h3>内联处理</h3>
    <button @click="addCount">Add</button>
    <p>{{ count }}</p>
</template>


<script>
  export default {
    data() {
      return{
        count:0
      },
	methods:{
        addCount(){
            this.count++;
        }
    }
    }

  }

</script>
事件传参

也就是说methodName(variable) 可以传递参数

其中,$event 表示传递事件对象

<template>
  <h3>事件传参</h3>
  <!-- $event 表示事件传参传递了一个event对象 -->
  <p @click="getNameHandler(item,$event)" v-for="(item,index) of names" key="index">{{ item }}</p>
</template>


<script>
export default {
  // data里的值都可以用this来索引到 
  data() {
    return{
      names:["iwen","ime","frank"]
    }

  },
  methods:{
    addCount(msg) {
      this.count++;
      console.log(msg);
    },
    getNameHandler(name,e){
      console.log(name); 
      console.log(e);
    }
  }

}

</script>

事件修饰符

​ 这里跳过了,好像没啥用

数组变化侦测

Vue会检测到变更方法对数组的更改,并在页面上同步更新数组,

names.push("Alice")

替换方法则需要按照以下代码形式使用:

this.numbers1 = this.numbers1.concat(this.numbers2);

会改变原数组的变更方法

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

不会改变原数组的替换方法

  • filiter()
  • concat()
  • slice()

计算属性

就是:

computed:{

} 内的方法

计算属性的用途:

  1. 比如下面这个

    标签内来判断itbanzhan.content的数组是否有内容

    把三目运算符放在computed内成为方法,有利于代码阅读

  2. 性能优化

    computed仅会计算一次,而methods内的方法每次调用都会执行一次

    也就是说,当这个页面有10个

    {{ itbaizhanContent }}

    时,computed内的itbaizhanContent()也只会执行一次

    而methods内的会执行10次

<template>
  <h3>{{ itbaizhan.name }}</h3>
  <p>{{ itbaizhanContent }}</p>
</template>

<script>

export default{
  data(){
    return{
      itbaizhan:{
        name:"百战程序员",
        content:["前端","Java","Python"]
      }
    }
  },
  //计算属性
  computed:{
    itbaizhanContent(){
      return this.itbaizhan.content.length >0 ? "Yes" : "No";
    }
  }
}


</script>

Class绑定

跟CSS有关

class绑定还是基于 v-bond ,但是和普通v-bond不同的是

class的v-bond支持绑定数组和对象

<template>
  <!-- 单对象绑定 -->
  <p :class="{ active: isActive, 'text-danger': hasError }">Class 样式绑定1</p>
  <!-- 多对象绑定 -->
  <p :class="classObject">Class 样式绑定2</p>
  <!-- 数组形式绑定 -->
  <p :class="[arrActive, arrHasError]">Class 样式绑定3</p>
  <!-- 三目运算符绑定 -->
  <p :class="[isActive?'active':'']">Class 样式绑定4</p>
  <!-- 数组和对象混合 -->
  <p :class="[isActive ? 'active':'',{ 'text-danger':hasError}]">Class 样式绑定5</p>

</template>

<script>
export default {
  data() {
    return {
      isActive: true,
      hasError: true,
      classObject: {
        active: true,
        'text-danger': true,
      },
      arrActive: 'active',
      arrHasError: 'text-danger',
    }
  },
}
</script>

<style>
.active {
  font-size: 30px;
}

.text-danger {
  color: red;
}
</style>

Style绑定

和class绑定同理,v-bond增强至数组和对象

侦听器

侦听器可以侦听
data(){
message:“Hello”
}

内定义的变量变化

侦听器是与data()、methods同级的watch:{}

watch内的一个方法对应监听一个变量

且方法名与被监听变量名要一致

watch:{
message(newValue,oldValue){

}

}

<template>
  <h3>侦听器</h3>
  <button @click="updataHandle">修改数据</button>

</template>

<script>
export default{
  data(){
    return{
      message:"hello"
    }
  },
  methods:{
    updataHandle(){
      this.message = "World"
    }
  },
  //侦听器
  watch:{
    //newVlaue是改变之后的数据
    //oldValue是改变之前的数据
    //函数名必须与侦听的数据对象保持一致
    message(newVlaue,oldValue){
      //数据发生变化,自动执行的函数
      console.log(newVlaue,oldValue)
    }
  }
}

</script>

表单输入绑定

v-model

v-model设置在标签里,绑定一个data()内的变量message

绑定的变量message会同步和Input内容更新

<template>
  <h3>表单输入绑定</h3>
  <form>
    <input type="text" v-model="message">
    <p>{{ message }}</p>
    <input type="checkbox" id="checkbox" v-model="checked">
  </form>
  <label for="checkbox">{{ checked }}</label>

</template>

<script>
export default{
  data(){
    return{
      message:"",
      checked:"false"
    }
  }
}
</script>

v-bond修饰符

.lazy——只有在change事件后才触发更新

.number——只能接受数字

.trim——消除空格

.lazy:

在输入过程中变量不会和输入一起更新,失去焦点这样的事件触发后才会同步更新

模板引用(DOM引用)

模板引用就是DOM引用

通过给标签设置属性 ref=“container”

后面可以在脚本中使用this.$refs.container,使用原生JS来操控该标签

<template>
  <div ref="container" class="container">{{ content }}</div>
  <button @click="getElementHandle">获取元素</button>
</template>

<script>
/**
 * 内容改变: {{ 模板语法 }}
 * 属性改变: v-bond
 * 事件:     @click=""
 * 
 * 没有特殊需求,不要操控DOM
*/
export default {
  data(){
    return{
      content:"内容"
    }
  },
  methods:{
    getElementHandle(){
      // innerHTML:原生JS的属性
      console.log(this.$refs.container.innerHTML = "hhhhh");
    }
  }
}
</script>

组件

组件组成
  1. 首先是文件构成和结构

    Vue页面分为两种:主文件App.vue和Component文件夹内的.vue文件

    Compnent内的.vue文件就是构成页面的组件

    主文件和组件文件一般都包含以下三个部分:

    <template>
    	<!-- html -->
    </template>
    <script>
    	// JavaScript
    </script>
    <style>
    	/* css */
    </style>
    
  2. 组件引入

    下面是组件Mycomponent引入主文件App.vue的例子

    MyComponent:

    <template>
      <div class="container">{{ message }}</div>
    </template>
    <script>
      export default {
        data(){
          return{
            message:"组件基础组成"
          }
        }
      }
    </script>
    <style>
    
    .container{
      font-size: 30px;
      color: brown;
    }
    
    </style>
    

    App.vue

    <template>
      <!-- 3.显示组件 -->
      <MyComponent/>
    </template>
    <script>
      //1. 引入组件
      import MyComponent from './components/MyComponent.vue';
    
      export default {
        //2. 注入组件
        components:{
          MyComponent
        }
      }
    </script>
    <style>
    
    </style>
    

Vue学习笔记——麻麻再也不用担心我的Vue!_第2张图片

  1. style scoped

    scoped的作用是限制生效作用域,一般用于组件内,使样式只能作用于本组件内的元素,

    如果元素被引用,样式不会作用于引用页面的元素

    举例:

    对于一个组件

    ComponentDemo.vue:

    <template>
    	<div class = 'title'>这是一个标题</div>
    </template>
    
    <style scoped>
        .title{
            font-size = 50px;
        }
    </style>
    

    APP.vue

    <template>
    	<div class = "title">App的标题</div>
    </template>
    <script>
      //1. 引入组件
      import MyComponent from './components/MyComponent.vue';
    
      export default {
        //2. 注入组件
        components:{
          MyComponent
        }
      }
    </script>
    

    如果没有scoped,APP.vue内的 标题因为与组件的class都是 title,

    会被组件内的style选择器命中,从而会有和组件标题同样的样式

组件嵌套关系

举个例子:

对于下图这个页面:

主要由五个组件构成:Header、Main、Asiede、Article和Item

引用结构:

------Header

App.vue ------Main -----Article

------Aside -----Item

Main组件内import了Article组件

Aside组件内Import了Item组件

App.vue则import了三个组件:Header、Main和Aside

以上便是组件的嵌套关系

Vue学习笔记——麻麻再也不用担心我的Vue!_第3张图片

组件的注册方式 ( 引入方式 )

分为全局注册局部注册

局部注册:
就是之前的三步骤,将一个组件引入另一个组件

全局注册:
在main.js内注册,注册后全局都可以在内引入并直接使用

main.js :

import { createApp } from 'vue'
import App from './App.vue'
import Header from './pages/Header.vue'


const app = createApp(App)
//在这之间进行组件注册

// 注册语句
app.component("Header",Header)

app.mount('#app')

尽量使用局部注册,局部注册的父子组件依赖关系比较明确

组件传递数据_Props
  1. 传递在组件之间
  2. 只能父组件传递给子组件
  3. 可以传递任何类型的数据
  4. Props内的变量是只读的,无法被修改

步骤:在父组件的template中,对子组件的展示标签增加属性,这些属性变量就是要传递过去的值

如果仅以 title="Parent"这种形式赋值,传递过去的数据是String型静态数据

如果想要动态数据,或者是数字、数组和对象型数据,就需要用 :age:" " 进行属性绑定,在data内定义变量的类型和值

Parent.vue

<template>
  <h3>Parent</h3>
  <Child title="Parent 数据" demo = "测试" :test="msg" :age="age" :names="names" :people="people"/>
</template>

<script>
import Child from './Child.vue';
  export default {
    data(){
      return{
        msg:"动态Message",
        age:20,
        names:["li",'ime'],
        people:{
          name:"Ak",
          age:16
        }
      }
    },
    components:{
      Child
    }
  }
</script>

Child.vue

<template>
  <h3>Child</h3>
  <p>{{ title }}</p>
  <p>{{ demo }}</p>
  <p>{{ test }}</p>
  <p>{{ age }}</p>
  <ul>
    <li v-for="(item,index) of names" :key="index">{{ item }}</li>
  </ul>
  <p>{{ people.name }} {{ people.age }}</p>
</template>

<script>
  export default {
    data(){
      return{
        
      }
    },
    props:["title","demo","test","age","names","people"]
  }
</script>
组件传递Props校验 (对类型的校验、默认值和必选项的校验)

简单props以数组方式接受父组件传递过来的各个变量
如上面:props:[“title”,“demo”,“test”,“age”,“names”,“people”]

如果要对Props进行校验,则要改写成下面的格式:

<script>
  export default {
    data(){
      return{
        
      }
    },
    props:{
        title:{
            type:[String,Number,Array,Object],
            required:true,
            default:"Test"
        },
        names:{
            type:[Array],
            default(){
                return ["空"]
            }
        }
    }
  }
</script>

type:[] 用数组来表示变量的类型限制,变量接收的数据只能是这几种

required: 表示该变量是否是必须的

default则为默认值…注意: 数字、字符串和布尔值可以直接default: ,但是其他类型要函数返回

组件事件 (可以实现子传父)

组件事件就是子组件methods中定义的一个方法,该方法内用this.$emit进行标识

举例:Child.vue 和 ComponentEvent.vue

Child.vue:

通过按钮触发chickEventHandle方法

该方法内的语句 this.$emit标识了该语句就是组件事件触发器

this.$emit() 方法接收一个或两个参数 ,第一个参数是父组件响应方法的方法名,第二个参数是传给父组件响应方法的参数(可选)

<template>
  <h3>Child</h3>
  <button @click="clickEventHandle">子按钮:传递数据</button>
</template>
<script>
  export default {
    data(){
      return{
        msg:"Child数据"
      }
    },
    methods:{
      clickEventHandle(){
        //自定义事件
        this.$emit("myEvent",this.msg)
      }
    }
  }
</script>

ComponentEvent.vue

父组件内,下引用的子组件标签要以

@myEvent=“methodsname” 的形式接收组件事件

其中 myEvent是响应子组件的名字,methodsname是父组件要调用的方法

<template>
  <h3>组件事件</h3>
  <Child @myEvent="fatherHandle"/>
  <p>{{ message }}</p>
</template>
<script>
import Child from './Child.vue';
  export default {
    components:{
      Child
    },
    data(){
      return{
        message:""
      }
    },
    methods:{
      fatherHandle(data){
        this.message = data
      }
    }
  }
</script>

以上,子组件也可以简写为 @click直接调用匿名函数

<button @click="$emit('increaseBy', 1)"> 

 Increase by 1 

</button>
组件事件配合v-model

一般来说是子父组件的输入v-model绑定

比如子组件Search.vue中有一个输入框,当子组件输入框输入数据时,父组件Main.vue会同步展示

原理:

子组件input框v-model绑定一个变量 search,search与input输入同步更新

同时子组件新增一个watch侦听变量search,同时通过组件事件this.$emit将search每次更新的新值传递给父组件

Search.vue:

<template>
  搜索:<input type="text" v-model="search">
</template>
<script>
  export default {
    data(){
      return {
        search:""
      }
    },
    watch:{
      search(newValue,oldValue){
        this.$emit("MainHandle",newValue)
      }
    }
  }
</script>

父组件在子组件标签内进行接收(这里用了简写的函数形式)

Main.vue

<template>
  <h3>Main</h3>
  <p>搜索内容为:{{ mes }}</p>
  <Search @MainHandle="data=>this.mes = data"/>
</template>
<script>
import Search from './Search.vue';
  export default {
      data(){
        return{
          mes:""
        }
      } ,
      components:{
        Search
      }
  }
</script>

效果展示:

Vue学习笔记——麻麻再也不用担心我的Vue!_第4张图片

组件Props子传父 (函数方法)

原理:

父组件A,子组件B

A有一函数Afunction,Afunction接收到的参数会赋值给msg, 声明在组件B标签里 func = “Afunction”

B会通过props设定func为Function,调用func函数,给func赋值,从而实现B的值传递给A(子传父)

ComponentA.vue

<template>
  <h3>ComponentA</h3>
  <ComponentB :func="Afunction"/>
  <p>A: {{ msg }}</p>
</template>

<script>
import ComponentB from './ComponentB.vue';
export default {
  data() {
    return {
      msg:""
    }
  },
  components:{
    ComponentB
  },
  methods:{
    Afunction(data){
      this.msg = data;
    }
  }
}
</script>

ComponentB.vue

<template>
  <h3>ComponentB</h3>
  <p>{{ func("从B传递的数据") }}</p>
</template>

<script>
export default {
  data() {
    return {
      
    }
  },
  props:{
    func:Function
  }
}
</script>
透传Atrribute

看着挺烦的

感觉这个功能会导致代码阅读混乱(

不学了

插槽
插槽基础

插槽实际就是在组件与组件之间,传递html模版,父组件传递给子组件

比如父组件想把 两行标题html代码传递给子组件,从而实现在子组件内展示该代码

实现原理:

父组件

父组件中对子组件标签的引用,由单标签变为双标签

比如子组件Chile.vue

则父组件中对子组件的引用就改为:

在两个子组件标签内放置要传递的Html模板内容

子组件

子组件在的某一位置放置

两个slot标签内部就是父组件传递过来的HTML模板代码,从而在子组件内展示


示例:

App.vue:

<template>
  <SlotsBase>
    <div>
      <h3>插槽标题</h3>
      <p>{{ msg }}</p>
    </div>
  </SlotsBase>
  <SlotsTwo>

  </SlotsTwo>
</template>
<script>
import SlotsBase from './components/SlotsBase.vue';

export default {
    data() {
        return {
			msg:"插槽内容"
        };
    },
    components: {
      SlotsBase,
      SlotsTwo
    }
}
</script>
<style>

</style>

SlotBase.vue:

<template>
  <h3>插槽基础知识</h3>
  <slot></slot>
</template>
<script>
  export default {
    
  }
</script>

Vue学习笔记——麻麻再也不用担心我的Vue!_第5张图片

插槽作用域

子组件通过插槽可以访问父组件的数据作用域

(上图有显示)

如果父组件通过插槽传递了

//

{{msg}}

而父组件同时在data内定义了msg:“Message”

子组件是可以通过插槽,访问到父组件变量msg的值的

插槽默认内容

很简单,子组件的两个slot标签内的内容就是缺省显示在屏幕上的,如果插槽传递了模板,则不显示

默认值默认值默认值

具名插槽

插槽可以有名字

这种情况主要用于,父组件向子组件传递多个模板,子组件分别而不是一次性接收这些模板

先看一下下面这种情况

父组件:

<template>
  <SlotsTwo>
    <div>
      <h3>插槽标题</h3>
      <p>插槽内容</p>
    </div>
  </SlotsTwo>
</template>
<script>
import SlotsBase from './components/SlotsBase.vue';
import SlotsTwo from './components/SlotsTwo.vue';

export default {
    data() {
        return {
        };
    },
    components: {
      SlotsTwo
    }
}
</script>
<style>

</style>

子组件:

<template>
  <h3>Slot1</h3>
  <slot></slot>
  <h3>Slot2</h3>
  <slot></slot>
</template>
<script>
export default {
  
}
</script>
<style>

</style>

父组件只有一对子组件标签,子组件有两对插槽出口标签

那么最终父组件传递的模板会在子组件中出现两次,如下图

Vue学习笔记——麻麻再也不用担心我的Vue!_第6张图片

下面进入具名插槽:

具名插槽就是给父组件中不同的插槽起名字,子组件通过插槽的名字锁定,在不同的位置接收插槽

父组件将每一组Slot用标签圈起来,在template标签中给名字

(v-slot)可以简写成#

template v-slot:Slot1>