Vue3:基础学习笔记

点击跳转到Vue.js学习参考文档

文章目录

vue3.0介绍

什么是Vue.js

1、前端开发框架
2、用于构建用户界面的渐进式框架
3、简化复杂的开发过程
4、Vue 也完全有能力为复杂的单页应用程序提供支持

安装

将 Vue.js 添加到项目中有四种主要方法:

1、在页面上将其导入为CDN包

<script src="https://unpkg.com/vue@next"></script>

2、下载 JavaScript 文件并自行托管
如果您想避免使用构建工具但不能在生产中使用 CDN,那么您可以下载相关.js文件并使用您自己的 Web 服务器托管它。然后您可以使用

3、使用npm安装
npm 是使用 Vue 构建大型应用程序时推荐的安装方法

4、使用官方CLI构建项目,该项目为现代前端工作流程(例如,热重载、lint-on-save 等)提供包含电池的构建设置
Vue 提供官方 CLI (打开新窗口)用于快速搭建雄心勃勃的单页应用程序

vite构建工具工具创建vue3项目

使用npm创建

前提安装Node.js
步骤如下:

$  npm init vite@latest <project-name>  或者   $  npm init vite-app <project-name>

$ cd <project-name>
$ npm install
$ npm run dev

使用yarn

$ yarn create vite <project-name> --template vue
$ cd <project-name>
$ yarn
$ yarn dev

vue3项目结构

在这里插入图片描述

Vue声明式语法与数据双向绑定

命令式

document.querySelector('h1').innerHTML="小范宝贝"

声明式

export default {
  name: "App",
  data(){
    return{
      msg:'小范同学'
    }
  },

  methods:{
    changeMsg(){
      this.msg = '小范美女'
    }
  }
};

数据双向绑定

数据变了,页面内容也会变,页面内容变了,数据也随之改变

    <h1 @click="changeMsg">{{msg}}</h1>
    <input type="text" v-model="msg"  />

在这里插入图片描述

模板语法

双括号语法

<h1>{{msg}}</h1>

v-once

一次性插值,只渲染一次

 <!-- v-once指令,使得内容只渲染一次 -->
    <h1 @click="changeMsg" v-once>{{msg}}</h1>

v-html

在内容中插入HTML代码

 <!--v-html指令 使得内容插入html的代码  -->
    <div>{{content}}</div>
     <div v-html="content"></div>

v-bind

绑定属性的内容

<!-- v-bind指令 绑定属性的内容 -->
 <div v-bind:id="id"></div>

模板语法中使用JavaScript表达式

<template>
  <div>
    <!-- JavaScript可以在模板语法中使用 -->
    <!-- 双括号语法 -->
    <h1>{{ msg }}</h1>
    <!-- split()分割msg字符串,得到一个数字 -->
    <h1>{{msg.split('')}}</h1>
    <!-- reverse() 使得数组内容颠倒 -->
    <h1>{{msg.split('').reverse()}}</h1>
    <!-- join()使得数组内容合并成字符串 -->
    <h1>{{msg.split('').reverse().join('')}}</h1>
    <!-- 可以使用三元运算符 -->
    <div>{{color=="green"?"开心":"难过"}}</div>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      msg: "Hello,Word!",
      color:"green"
    };
  },
  methods: {
  },
};
</script>

在这里插入图片描述

动态指令

指令对应的属性名称是可以修改的

<template>
  <div>
    <!-- 动态指令 -->
    <div v-bind:[attrbuteName]="d1"></div>
    <button @click="toggleColor">点击切换颜色</button>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     attrbuteName:"class",
     d1:'d1'
    };
  },

  methods: {
    toggleColor() {
      this.attrbuteName = "id";
    },
  },
};
</script>

<style>
  #d1{
    margin-left: 47%;
    width: 100px;
    height: 100px;
    background-color: yellow;
  }
  .d1{
    margin-left: 47%;
    width: 100px;
    height: 100px;
    background-color: blue;
  }
</style>

计算属性

  • 简化代码
<template>
  <div>
    <!-- 原来的msg -->
    <h1>{{msg}}</h1>
    <!-- 运用JS语句颠倒msg -->
    <h1>{{msg.split('').reverse().join('')}}</h1>
    <!-- 使用计算属性颠倒msg -->
    <h1>{{reverseMsg}}</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     msg: 'Hello World'
    };
  },
  computed:{
    reverseMsg(){
      return this.msg.split('').reverse().join('')
    }
  },

  methods: {
    toggleColor() {
      this.attrbuteName = "id";
    },
  },
};
</script>

watch监听数据的变化

想要监听数据的变化,可以使用watch监听,里面写监听目标变量的函数,里面有两个参数,第一个参数是新值,第二个参数是旧值。

<template>
  <div>
    <!-- 原来的msg -->
    <h1>{{msg}}</h1>
    <input type="text" v-model="msg">
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     msg: 'Hello World'
    };
  },
  
  watch:{
    msg(newValue,oldValue){
      if(newValue.length<10){
        alert("输入的值太少了!!!")
      }

    }
  }
  
};
</script>

类的多种绑定方式

放置字符串

<template>
  <div>
    <!--class -->
    <!-- 第一种写法,放置字符串 -->
    <h1 v-bind:class = "msg">hello</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     msg: 'Hello World'
    };
  },
};
</script>

在这里插入图片描述

放置对象

<template>
  <div>
    <!--class -->
   <!-- 放置对象 -->
   <h1 v-bind:class="{active:isActive}">Hello</h1>
   <button @click="toggleActive">切换样式</button>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     isActive: true
    };
  },

  methods:{
    toggleActive(){
      this.isActive=!this.isActive
    }
  }
  
  
};
</script>
<style scoped>
  .active{
    background-color: yellow;
  }
</style>

在这里插入图片描述

放置数组

<template>
  <div>
    <!--class -->
   <!-- 放置数组 -->
   <h1 :class="arr">Hello</h1>
   <button  @click="toggleActive">切换类</button>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     arr: ['swiper','active']
    };
  },

  methods:{
    toggleActive(){
      this.arr.pop()
    }
  }
};
</script>

在这里插入图片描述

数组和对象的结合

<template>
  <div>
    <!--class -->
    <!-- 数组和对象的结合 -->
    <h1 :class="[className, {active:isActive}]">Hello</h1>
    <button @click="toggleActive">切换类</button>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     className : "abc",
     isActive : true
    };
  },

  methods:{
    toggleActive(){
      this.className= "cba",
      this.isActive = !this.isActive
    }
  }
  
  
};
</script>
<style scoped>
.active {
  background-color: yellow;
}
</style>

在这里插入图片描述
在这里插入图片描述

Style样式的多种绑定方式

放置字符串

<template>
  <div>
    <!--class -->
    <!-- 第一种写法:放置字符串 -->
    <h1 :style="msg">Hello</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     msg: "background:red;"
    };
  },
};
</script>

在这里插入图片描述

放置对象

<template>
  <div>
    <!--class -->
    <!-- 第一种写法:放置字符串 -->
    <h1 :style="{background: 'purple'}">Hello</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
     
    };
  },
};
</script>

在这里插入图片描述

放置数组

<template>
  <div>
    <!--class -->
    <!-- 第一种写法:放置字符串 -->
    <h1 :style="[styleObj,{boxSizing: 'border-box'}]">Hello</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      styleObj:{
        background: "pink",
        border: '1px solid blue'
      }
     
    };
  },
};
</script>

在这里插入图片描述

v-if 和 v-show

  • v-if…v-else-if…v-else… 可以根据不同的条件显示多个内容,频繁切换的话,较为消耗性能

  • v-show 根据条件确定是否显示单个内容,不显示时,其实是将样式改为display: none 所以性能消耗较小

<template>
  <div>
    <!-- 设置多个内容切换显示 -->
   <h1 v-if = "user == '超级VIP'"> 欢迎金主爸爸</h1>
   <h1 v-else>充值使你更强大</h1>
   <button @click="toggleUser">切换用户</button>

   <!-- 设置一个内容切换显示 -->
    <h1 v-show="isShow">只显示我一个</h1>
    <button @click="toggleShow">切换</button>

  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      user:'超级VIP',
      isShow: true
    };
  },

  methods:{
    toggleUser(){
      this.user = "普通用户"
    },
    toggleShow:function(){
      this.isShow = !this.isShow
    }
  }
};
</script>

在这里插入图片描述

v-for循环

  • 循环数组
  • 循环数组里的对象
  • 循环对象
<template>
  <div>
    <!-- 循环数组 -->
    <ol>
      <li v-for="(item, i) in news" :key="i">{{ item }}====>{{ i }}</li>
    </ol>
    <!-- 循环数组里的对象 -->
    <ol>
      <li v-for="(item, i) in news1" :key="i">
        {{ item.title }}==>{{ item.content }}===>{{ item.athor }}====>{{ i }}
      </li>
    </ol>
    <!-- 循环对象 -->
    <ol>
      <li v-for="(item, i) in athor" :key="i">{{ item }}====>{{ i }}</li>
    </ol>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      news: ["11111", "222222", "333333"],
       news1: [
      {
        title: "我是标题1",
        content: "我是内容1",
        athor: "作者1",
      },
      {
        title: "我是标题2",
        content: "我是内容2",
        athor: "作者2",
      },
    ],
    athor:{
      name:'lingLing',
      age: '18'
    }
    }
   
  },
};
</script>

在这里插入图片描述

事件与参数、时间修饰符

绑定事件使用 v-on(简写@)

  • 绑定事件不需要参数
<h1 @click="addEvent">{{num}}</h1>
  • 绑定事件,直接处理表达式
 <h1 @click="num += 2">{{num}}</h1>
  • 绑定事件,传递参数
 <h1 @click=" addEvent1(20)">{{num}}</h1>
  • 绑定事件。传递 $event事件对象和参数
<h1 @click=" addEvent1(20,$event)">{{num}}</h1>
  • 一个事件绑定多个处理函数
 <h1 :style="{background:color}" @click="addEvent1(20,$event),changeColor($event)">{{num}}</h1>

事件修饰符

  • 阻止事件冒泡 .stop
  • 阻止默认事件 .prevent
  • 事件只触发一次 .once
<h1 @click.once=" addEvent1(20,$event)">{{num}}</h1>  

按键修饰符

enter/tap.delete/esc/space/up/down/left/right

 <input type="text" @keydown.enter="searchEvent">

系统修饰符

.ctrl/.alt/.shift/.meta

鼠标修饰符

.left/.right/.middle
<template>
  <div>
    <!-- 绑定事件,不需要参数 -->
    <h1 @click="addEvent">{{num}}</h1>
    <!-- 绑定事件,直接处理表达式 -->
    <h1 @click="num += 2">{{num}}</h1>

    <!-- 绑定事件,传递参数 -->
    <h1 @click=" addEvent1(20)">{{num}}</h1>
    <!--绑定事件。传递 $event事件对象和参数 -->
    <h1 @click=" addEvent1(20,$event)">{{num}}</h1>  

    <!-- 一个事件绑定多个处理函数 -->
    <h1 :style="{background:color}" @click="addEvent1(20,$event),changeColor($event)">{{num}}</h1>

    <!-- 事件修饰符 -->
    <!-- 
      阻止事件冒泡 .stop
      阻止默认事件 .prevent
      事件只触发一次 .once
     -->
    <h1 @click.once=" addEvent1(20,$event)">{{num}}</h1>  
    
    <!-- 按键修饰符
    enter/tap.delete/esc/space/up/down/left/right
    系统修饰符
    .ctrl/.alt/.shift/.meta
    鼠标修饰符
    .left/.right/.middle
     -->
    <input type="text" @keydown.enter="searchEvent">
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      num:0,
      color: 'red'
    }
  },
  methods:{
     addEvent:function(e){
       console.log(e)
       this.num += 2
     },

     addEvent1:function(number){
       this.num += number
     },

      addEvent2:function(number,event){
       this.num += number
     },

     changeColor:function(){
       this.color = 'pink'
     },
     searchEvent:function(){
       console.log("执行了搜索事件!!!")
     }
   }
};
</script>
 

在这里插入图片描述

表单输入双向绑定、修饰符

文本框 text

*单行本文框数据的双向绑定

<input v-model="searchKey" type="text" @keydown="searchEvent" />

多行文本框textarea

  • 多行文本框的数据绑定
<textarea v-model="lineText" name="textarea"  id="" cols="30" rows="10"></textarea>

复选框checkbox

  • 复选框的数据绑定,获取的是是否选中的内容
<input type="checkbox" name="likes" v-model="fruits" value="柿子">
    <input type="checkbox" name="likes" v-model="fruits" value="香蕉">
    <input type="checkbox" name="likes" v-model="fruits" value="葡萄">
    <input type="checkbox" name="likes" v-model="fruits" value="苹果">

单选框radio

只能选一个值

<input type="radio" name="sex" value="man" v-model="picked">
<input type="radio" name="sex" value="woman" v-model="picked">

选项框 select

添加multiple属性可以选择多个选项

<select name="citys"  v-model="citys" multiple >
      <option value="广州"></option>
      <option value="上海"></option>
      <option value="北京"></option>
      <option value="成都"></option>
    </select>

数据绑定v-model的修饰符

.lazy

input变为change事件改变值,焦点失焦后才改变

<input v-model.lazy="searchKey1" type="text" @keydown="searchEvent" />

.number

把输入值转换为数字类型

<input v-model.lazy.number="searchKey2" type="text" @keydown="searchEvent" />

.trim

去掉空格

 <input v-model.lazy.trim="searchKey3" type="text" @keydown="searchEvent" />

案例代码

<template>
  <div>
    <!-- 单行本文框数据的双向绑定 -->
    <input v-model="searchKey" type="text" @keydown="searchEvent" />
    <h1>{{ searchKey }}</h1>

    <!-- 多行文本框的数据绑定 -->
    <textarea v-model="lineText" name="textarea"  id="" cols="30" rows="10"></textarea>
    <h1>{{ lineText }}</h1>

    <!-- 复选框的数据绑定,获取的是是否选中的内容-->
    <input type="checkbox" name="like" v-model="checked" value="123">
    <h1>{{checked}}</h1>
    <!-- 复选框多个值的情况 -->
    <input type="checkbox" name="likes" v-model="fruits" value="柿子">
    <input type="checkbox" name="likes" v-model="fruits" value="香蕉">
    <input type="checkbox" name="likes" v-model="fruits" value="葡萄">
    <input type="checkbox" name="likes" v-model="fruits" value="苹果">
    <h1>{{fruits}}</h1>

    <!-- 单选框的数据绑定 -->
    <input type="radio" name="sex" value="man" v-model="picked">
    <input type="radio" name="sex" value="woman" v-model="picked">
    <h1>{{picked}}</h1>

    <!-- 单选选项框的数据绑定 -->
    <select name="city"  v-model="city">
      <option value="广州"></option>
      <option value="上海"></option>
      <option value="北京"></option>
      <option value="成都"></option>
    </select>
    <h1>{{city}}</h1>

    <!-- 多选选项框的数据绑定 -->
    <select name="citys"  v-model="citys" multiple >
      <option value="广州"></option>
      <option value="上海"></option>
      <option value="北京"></option>
      <option value="成都"></option>
    </select>
    <h1>{{citys}}</h1>

    <!-- 表单获取的是是否选中的内容 -->
    <input type="checkbox" name="like" v-model="checked1" true-value="喜欢" false-value="不喜欢">
    <h1>{{checked1}}</h1>

    <!-- 修饰符 -->
    <!-- .lazy/input变为change事件改变值,焦点失焦后才改变 -->
    <input v-model.lazy="searchKey1" type="text" @keydown="searchEvent" />
    <h1>{{searchKey1}}</h1>

    <!-- .number 把输入值转换为数字类型 -->
    <input v-model.lazy.number="searchKey2" type="text" @keydown="searchEvent" />
    <h1>{{searchKey2}}</h1><input v-model.lazy.trim="searchKey3" type="text" @keydown="searchEvent" />
    <h1>{{searchKey3}}</h1>
  </div>
</template>

<script>
// 声明式
export default {
  name: "App",
  data() {
    return {
      searchKey: "百度一下",
      lineText: "",
      checked: false,
      fruits:[],
      picked:'',
      city:'',
      citys:[],
      checked1:'',
       searchKey1: "百度一下",
       searchKey2:'转换为数字类型',
       searchKey3:'去掉空格'
    };
  },
  methods: {
    searchEvent: function () {
      console.log("执行了搜索事件!!!");
    },
  },
};
</script>

组件

父组件向子组件传递数据props

父组件数据newContent绑定在content ,子组件通过props接收父组件的数据
父组件 App.vue代码如下:

<template>
  <div>
    <!-- 父组件数据newContent绑定在content  -->
    <News :content = "newsContent"></News>
  </div>
</template>

<script>
// 声明式
import News from './components/News.vue'
export default {
  name: "App",
  data() {
    return {
      newsContent:"23岁女星与男子开房被原配抓包!!!"
    };
  },
  methods: {
    
  },
  components:{
    News
  }
};
</script>

子组件 App.vue代码如下:

<template>
    <div>
        <h1>新闻内容是{{content}}</h1>
    </div>
</template>
<script>
export default {
    // 子组件通过props接收父组件的数据
    props:["content"]
}
</script>

通过provide和inject 将数据提供给子组件

父组件通过provide()将数据提供出去,子组件通过inject()将数据注入进来
父组件代码:App.vue

<template>
  <div>
    <Student></Student>
  </div>
</template>

<script>
import { reactive,provide} from "vue";
import Student from './components/Student.vue'
export default {
  name: "App",
  data() {
    return {
     
    };
  },
  setup() {
     const student = reactive({
      name: "小红",
      age: 18,
      grade: "初一",
    });
    // 将数据提供出去
    provide("stu", student);
    
    return { };
  },
  components:{
    Student
  },
};
</script>

子组件代码:Student.vue

<template>
  <div>
    <h1>userName:{{ name }}</h1>
    <h1>age: {{ age }}</h1>
    <h1>年级:{{grade}}</h1>
  </div>
</template>

<script>
import { inject } from "vue";
export default {
  setup() {
    // 将父组件提供的数据注入进来
   const student = inject('stu')
   return {...student}
  },
};
</script>

运行截图如下
在这里插入图片描述

子组件向父组件传递数据:自定义事件

子组件触发自定义事件1,父组件监听自定义事件1,并将监听到的值给自定义事件2
App.vue代码如下:

<template>
  <div>
    <!-- 子组件将数据传递给父组件,监听到sendParentMsg被触发就会运行自定义事件sendChildMsg -->
    <Login @sendParentMsg ="getChildMsg" ></Login>
    <h1>从子元素获得的值:{{msg}}</h1>

  </div>
</template>  

<script>
// 声明式
import Login from './components/Login.vue'
export default {
  name: "App",
  data() {
    return {
      msg:''
    };
  },
  methods: {
    getChildMsg:function(value){
      this.msg = value
    }
    
  },
  components:{
    Login
  }
};
</script>

Login.vue代码如下:

<template>
    <div>
        <input type="text" v-model="userName">
        <button @click="sendMsg">将数据提交给父组件</button>
    </div>
</template>

<script>
export default {
    data(){
        return{
            userName:''
        }
    },
    methods:{
        sendMsg:function(){
            // 使用$emit(事件名称,发送的事件值)触发自定义事件 sendParentMsg()
            this.$emit("sendParentMsg",this.userName)
        }
    },
}
</script>

Vue3生命周期

beforeCreate()和created()

初始化数据之前和初始化数据之后,初始化页面时调用

beforeMount()和mounted()

挂载渲染之前和挂载渲染之后,初始化完成后开始渲染页面

beforeUpdate()和updated()

页面数据发生更改时调用

beforeUnmount()和unmounted()

页面数据不显示时不渲染,vue2调用的是 beforeDestroy()和destroyed()

合成API:Composition API

  • 可以在setup函数中使用Composition AP

  • 普通写法和合成API的写法执行顺序,合成API更加快速便捷,且有利于代码的维护
    在这里插入图片描述

Composition API :单个值ref

导入ref
ref()是一个变量变成响应式的

import {ref} from 'vue'
<template>
  <div>
    <h1 @click="changeEvent">普通方式计数:{{count}}</h1>
     <h1 @click="num+=10">使用合成API计数:{{num}}</h1>
  </div>
</template>

<script>
import {ref} from 'vue'

export default {
  name: "App",
  data() {
    return {
      count: 0
    };
  },
  setup(){
    const num = ref(0)
    return{num}
  },
  methods: {
   changeEvent() {
      this.count++
    },
  },

};
</script>

Composition API :函数

<template>
  <div>
     <h1 @click="changeNum">使用合成API定义的函数计数:{{num}}</h1>
  </div>
</template>

<script>
import {ref} from 'vue'

export default {
  name: "App",
  data() {
    return {
    };
  },
  //合成API
  setup(){
  //实例化变量 num
    const num = ref(0)
    function changeNum(){
        num.value += 10
    }
    //返回相关的变量和函数
    return{num,changeNum}
  },
};
</script>

Composition API :对象 reactive({})

  • reactive({})使得一个对象变成响应式的
  • …toRefs(对象名)是用于解构对象,调用对象属性时不需要带上对象名作为前缀
<template>
  <div>
    <!-- 合成API中对象的使用 -->
    <h1>姓名:{{user.userName}}</h1>
    <!-- 合成API中返回的是解构对象,调用时不用加对象名前缀 -->
    <h1>年龄:{{age}}</h1>
    <h1 @click="changeType">类型:{{type}}</h1>
  </div>
</template>

<script>
import { reactive,toRefs} from "vue";
export default {
  name: "App",
  data() {
    return {
    };
  },
  setup() {
    // 定义对象
    const user = reactive({
      userName: "小米",
      age: 18,
      type: "小奶狗",
    });
    // 更改对象数据
    function changeType(){
      user.type = "超级帅!!!"
    }
    //...toRefs(user)是解构对象
    return { num, changeNum, user, ...toRefs(user),changeType};
  },
};
</script>

Composition API :监听数据变化

watchEffect

跟踪所使用到的数据的变化

导入

import { watchEffect} from "vue";
//只跟踪匿名函数里使用到的值type
    watchEffect(()=>{
      console.log(user.type)
      console.log("user.type的值发生改变时触发")
    })

watch

跟踪指定属性
导入

import { watch} from "vue";
  • 监听单个属性
// 单个监听
      watch(num,(newNum,oldNum)=>{
      console.log(newNum)
      console.log(oldNum)
      console.log("num的值发生改变时触发")
    })
  • 监听多个属性
// 多个监听
     watch([num,user],(newNum,oldNum)=>{
      console.log(newNum)
      console.log(oldNum)
      console.log("值发生改变时触发")
    })

setup详解

使用setup接收父组件数据

需要依赖props接收数据,父组件先绑定数据,子组件通过props接收,在setup中可以通过props计算响应式内容

  • content属性包含了父组件中传过来的内容

子组件的代码:

<template>
    <div>
        <h1>userName:{{userName}}</h1>
        <h1>age: {{age}}</h1>
        <!-- 通过props生成一句话 -->
        <h1>description: {{description}}</h1>
    </div>
</template>

<script>
import {ref} from 'vue'
export default {
    setup(props,content){
        // 使用setup接收props的数据,通过props计算响应式的内容
        const description = ref(props.userName+"年龄是"+props.age)
        console.log(content)
        return{description}

    },
    // 接收来自父组件绑定的数据
    props:['userName','age']
}
</script>

父组件代码:

<template>
  <div>
    <User :userName = "userName" :age= "age" class="abc"></User>
  </div>
</template>

<script>
import { reactive,toRefs} from "vue";
import User from './components/User.vue'
export default {
  name: "App",
  data() {
    return {
     
    };
  },
  setup() {
    // 定义对象
    const user = reactive({
      userName: "小米",
      age: 18,
      type: "小奶狗"
    })
    
    //...toRefs(user)是解构对象
    return {  user, ...toRefs(user)};
  },
  components:{
    User
  },
};
</script>

生命周期

  • onBeforeMount 挂载渲染之前
  • onMounted 挂载渲染之后
  • onBeforeUpdate 更新之前
  • onBeforeUnmount 更新之后
    先导入
import {onBeforeMount,onMounted,onBeforeUpdate,onBeforeUnmount} from 'vue'

再运用

  setup(){
        // 声明周期函数的应用
        onBeforeMount(()=>{
            console.log("onBeforeMount")
        })
    },

Vue3路由:vue-router

路由的基本使用

  • 路由:单页面应用根据路径的变化显示不同的内容
  • 在项目路径下安装路由
E:\vuejs\vue3Router01> npm install vue-router@next

HTML
App.vue代码:

<template>
  <div>
    <p>
      <router-link to="/">Go to Home</router-link>
      <router-link to="/about">Go to About</router-link>
    </p>

    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: "App",
};
</script>

JS
index.js

import {createRouter,createWebHashHistory} from 'vue-router'

const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

const router = createRouter({
  history:createWebHashHistory(),
  routes,
})

export default router

main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

import router from './router'

const app = createApp(App)

// 使用路由
app.use(router)

app.mount('#app')

动态路由

单页面应用中,根据路径的id显示不一样的内容

index.js

import {createRouter,createWebHashHistory} from 'vue-router'
//导入组件
import News from '../components/News.vue'
import NotFound from '../components/NotFound.vue'
//将组件加进路由里
const routes = [
  {path:'/news/:id',component: News},
  {path:'/:path(.*)',component: NotFound}
]

const router = createRouter({
  history:createWebHashHistory(),
  routes,
})

export default router

news.vue

<template>
    <div>
        <h1>新闻页{{$route.params.id}}</h1>
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$route)
    }
}
</script>

NotFound.vue

<template>
    <div>
        <h1>找不到页面</h1>
    </div>
</template>

在这里插入图片描述
在这里插入图片描述

路由正则与重复参数

  • \d+: id必须是数字
  • +: id至少有一个
  • *: id可有可无可重复可多个
  • ? : id可有可无,不可重复,不可多个

index.js

mport News from '../components/News.vue'
import Article from '../components/Article.vue'
import Film from '../components/Film.vue'
import Song from '../components/Song.vue'
import Vidio from '../components/Vidio.vue'
import NotFound from '../components/NotFound.vue'

const routes = [
  {path:'/news/:id',component: News},
  // \d+: id必须是数字
  {path:'/article/:id(\\d+)',component: Article},
  // + : id至少有一个
  {path:'/film/:id+',component: Film},
  // * : id可有可无可重复可多个
  {path:'/song/:id*',component: Song},
  // ? : id可有可无,不可重复,不可多个
  {path:'/vidio/:id?',component: Vidio},
]

嵌套路由

某些应用程序的 UI 由嵌套多级深的组件组成。在这种情况下,一个 URL 的参数(id)不同,对应嵌套组件的结构也不同,主结构相同,嵌套结构不同
index.js关键代码如下:

import User from '../components/User.vue'
import Hengban from '../components/Hengban.vue'
import Shuban from '../components/Shuban.vue'

const routes = [
  {path:'/user/',
  component: User,
  children:[
    {path:'hengban',component:Hengban},
    {path:'shuban',component:Shuban}
  ]
},
]

User.vue

<template>
    <div>
        <h1>user页面</h1>
        <router-view></router-view>
    </div>
</template>

Hengban.vue

<template>
    <div>
        <h1>这是横版页面</h1>
    </div>
</template>

Shuban.vue

<template>
    <div>
        <h1>这是竖版页面</h1>
    </div>
</template>

竖版运行视图
在这里插入图片描述

程序化导航:使用js跳转页面

导航到其他位置

除了<router-link to="url">用于创建用于声明性导航的锚标记之外,我们还可以使用路由器的实例方法以编程方式完成此操作。
在这里插入图片描述

  1. 参数可以是字符串路径
this.$router.push("/news/:id")
  1. 参数是具有path的对象
this.$router.push({path: '/news/:id'})
// 携带参数跳转
this.$router.push({path: '/news/123456'})
  1. 带参数的命名路由,让路由器构建路径
this.$router.push({name:'film',params:{id:123}})
  1. 带查询querry的路径
 this.$router.push({path:'/vidio',query:{search:'弯弯作死'}})

替换当前位置

 this.$router.replace({path: '/news/123456'})

替换当前位置

此方法采用单个整数作为参数,指示在历史堆栈中前进或后退的步数,类似于window.history.go(n)。

<button @click="$router.go(1)">前进</button>
<button @click="$router.go(-1)">后退</button>

命名路由与重定向和别名

命名路由

您可以拥有多个router-view并为每个router-view命名,一个router-view没有名字的将default作为它的名字。

App.vue关键代码

<router-view name="ShopTop"></router-view>
<router-view></router-view>
<router-view name="ShopFooter"></router-view>

index.js关键代码

import ShopMain from '../components/ShopMain.vue'
import ShopTop from '../components/ShopTop.vue'
import ShopFooter from '../components/ShopFooter.vue'

 {
    path: '/shop',
    components: {
      default:ShopMain,
      ShopTop:ShopTop,
      ShopFooter:ShopFooter
    }
  },

ShopMain.vue关键代码

<template>
    <div>
        <h1>ShopMain主要内容</h1>
    </div>
</template>

ShopTop.vue关键代码

<template>
    <div>
        <h1>ShopTop头部组件</h1>
    </div>
</template>

ShopFooter.vue关键代码

<template>
    <div>
        <h1>ShopFooter底部组件</h1>
    </div>
</template>

在这里插入图片描述

重定向:redirect

  • 重定向也在routes配置中完成。从/a到重定向/b:
const routes = [{ path: '/home', redirect: '/' }]
  • 重定向还可以针对命名路由:
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
  • 重定向还可以使用一个函数进行动态重定向
    就是说输入/mall路由就会跳转到/shop页面
const routes = [
	{
    path:'/mall',
    redirect:(shop)=>{
      return {path:'/shop'}
    }
  },
]

别名:alias

/shop的别名/home意味着当用户访问时/store,URL 仍然存在/store,但它会像用户正在访问一样匹配/shop。通过通过数组取多个别名

{
    path: '/shop',
    alias: '/store',
    components: {
      default:ShopMain,
      ShopTop:ShopTop,
      ShopFooter:ShopFooter
    }
  },

路由模式

哈希模式

使用哈希模式URL会出现一个 # ,URL 的这部分永远不会发送到服务器,所以它不需要在服务器级别进行任何特殊处理

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})

HTML5模式

使用HTML5模式,URL 将看起来“正常”,请求会发送到服务器。所以需要配置适当的服务器

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
})

导航守卫

Vue router 提供的导航守卫主要用于通过重定向或取消导航来保护导航。有多种方法可以连接到路由导航过程:全局、每个路由或组件内。

router.beforeEach

全局导航前守卫
index.js

router.beforeEach((to, from,next) => {
  // ...
  // explicitly return false to cancel the navigation
  console.log(to)
  console.log(from)
  next()
})

从store页面跳转到page页
从store页面跳转到page页

router.beforeResolve

全局保护,当路由跳转完成之后触发

router.beforeResolve(async to => {
  if (to.meta.requiresCamera) {
    try {
      await askForCameraPermission()
    } catch (error) {
      if (error instanceof NotAllowedError) {
        // ... handle the error and then cancel the navigation
        return false
      } else {
        // unexpected error, cancel the navigation and pass the error to the global handler
        throw error
      }
    }
  }
})

beforeEnter

单路由保护,进入路由前触发

 {
    path: '/shop',
    alias: '/store',
    components: {
      default: ShopMain,
      ShopTop: ShopTop,
      ShopFooter: ShopFooter
    }
  },

从store页面跳转到page页
在这里插入图片描述

组件内防护

写在组件里面的

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
 // 组件内导航防护
  beforeRouteEnter() {
    console.log("路由进入组件");
  },
  beforeRouteUpdate() {
    console.log("路由更新");
  },
  beforeRouteLeave() {
    console.log("路由离开");
  },

状态管理

通过reactive响应式对象管理

通过reactive响应式对象,再通过依赖provide和inject注入子组件中
index.js

import { reactive} from 'vue'

// 状态管理仓库
const store = {
    state : reactive({
        message:"你好"
    }),
    setMessage(value){
        this.state.message = value;
    }
}
export default store

父组件:App.vue

import store from './store/index.js'
export default {
provide:{
    store
  }
}

子组件:HelloWord.vue

inject:['store']

Vuex状态管理

home.vue
调用$store

<template>
  <div class="home">
    <h1>商品数量:{{ $store.state.count }}</h1>
    <h2>商品价格:100</h2>
    <h1>商品总价:{{ $store.getters.totalPrice }}</h1>
    <button @click="changeEvent">添加数量</button>

    <h1>段子</h1>
    <p v-for="(item,i) in $store.state.dzList" :key="i">{{item.text}}</p>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";

export default {
  name: "Home",
  components: {
    HelloWorld,
  },
  methods: {
    changeEvent: function () {
      // 触发状态的方法
      // 触发无参数的方法
      // this.$store.commit("setCount");
      // 触有参数的方法
      this.$store.commit("setCountNum", 3);
    },
  },
  mounted:function(){
    this.$store.dispatch('getDz')
  }
};
</script>

index.js
使用store

import { createStore } from 'vuex'

// 管理全局所用到的数据
export default createStore({
  // 设置全局数据
  state: {
    count:0,
    dzList:[]
  },
  /**
   * 含计算属性的方法
   */
  getters:{
    totalPrice:function(state){
      return state.count*100
    }

  },

 /**
  * 同步的方法
  * 修改状态的方法
  */
  mutations: {
    // 无参数
    setCount:function(state){
      state.count++;
    },
    // 有参数
    setCountNum:function(state,num){
      state.count+=num;
    },

    setDzList:function(state,arr){
      state.dzList = arr;
    }
  },
  /**
   * 异步的方法
   * 使用Ajax请求修改数据
   */
  actions: {
    getDz:function(context){
      // 开放免费的API
    let api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text";
    // 发出请求
    fetch(api)
      .then((res) => res.json())
      .then((result) => {
        console.log(result)
        context.commit('setDzList',result.result)
      });
    }
  },
  modules: {
  }
})

map辅助函数

  • mapState
  • mapGetters
  • mapMutations
  • mapActions
    map映射可以使得数据调用更加方便,不用加上$store.state,可以直接使用变量名
    组件Home.vue
import {mapState, mapGetters,mapMutations,mapActions} from 'vuex'

export default {
  name: "Home",
  components: {
    HelloWorld,
  },
  /**
   * 把状态映射到组件上
   * 直接调用数据
   */
  computed:{
  //映射数据
    ...mapState(['count']),
    ...mapState({
      productCount:(state)=>state.count
    }),
    //映射计算属性
    ...mapGetters(['totalPrice'])
  },
  methods: {
    changeEvent: function () {
      this.$store.commit("setCountNum", 3);
    },
    //映射改变状态的方法
    ...mapMutations(['setCountNum']),
    ...mapActions(['getDz'])
  },
  mounted:function(){
    this.$store.dispatch('getDz')
  }
};

vue3 实现前后端交互

通过fetch()

关键代码段

// 获取数据显示到页面
  setup() {
    // 开放免费的API
    let api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text";
    // 发出请求
    fetch(api)
      .then((res) => res.json())
      .then((result) => {
        store.setDzList(result.result);
        console.log(result.result);
      });
  return {
      store
    };

通过axios()

终端安装axios:npm install axios --save

import axios from 'axios'

 // 获取数据显示到页面
  setup() {
    // 开放免费的API
    let api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text";
    // 发出请求
    axios.get(api).then((result)=>{
       console.log(result)
       store.setDzList(result.data.result)
      // store.setDzList(result);
    })
    return {
      store
    };
  },

vite 配置跨域请求

跨域配置文件vite.config.js

/**
 * 跨域服务器的配置文件
 */

module.exports = {
    proxy :{
        '/api':{
            target: 'https://pvp.qq.com/',
            changeOrigin:true, //是否允许跨域
            rewrite:  path => path.replace(/^\/api/,'')
        }
    }
   
}

Mock.js 模拟获取数据

链接: 点击跳转到官网.
可以拦截 Ajax 请求,返回模拟的响应数据

index.js

import Mock from 'mockjs'
Mock.mock(
    "/user/userinfo",
    "get",
    (req,res)=>{
        console.log(req,res)
        return{
            username:"老陈",
            type:"帅!"
        }
    }
)

vue脚手架cli的使用

安装脚手架cli
npm install -g @vue/cli

查看版本
vue --version

创建项目
vue create vueproject01

选择版本
在这里插入图片描述

切换到项目路径
cd vueproject01

运行

npm run serve

模块化管理 vuex

在store中导入模块user,user1

import { createStore } from 'vuex'
import user from './user.js'
import user1 from './user1.js'

// 管理全局所用到的数据
export default createStore({
  // 设置全局数据
  state: {
   ...
  },
  getters:{
   ...
  },

  mutations: {
  ...
  },
  actions: {
	...
  },
  modules: {
    user,
    user1
  }
})

user模块,user.js代码如下:

/**
 * 用户模块
 */

const user = {
    state: () => ({
        username: "老陈",
        age: 30
    }),
    mutations: {
        setUsername:function(state){
            state.username = "小陈"
        },
        setAge:function(state){
            state.age = 40
        }
    },
    actions: {
        asyncSetAge:function(context){
            setTimeout(()=>{
                context.commit('setAge')
            },3000)
        }
    },
    getters: {
        description:function(state,getters,rootState){
            return state.username + '的年龄是' + state.age+'岁!'
        }
    }
}

export default user

命名空间

作用:区分每个模块,以防每个模块的getters和actions肯定会出现同名的情况

const user = {
    //  命名空间
    namespaced: true,
	.....
export default user

路由中的渲染User.vue
要加上模块名

  <!-- 命名空间的写法 -->
    <h1>用户名:{{ $store.state.user1.username }}</h1>
    <h1>年龄:{{ $store.state.user1.age }}</h1>
    <h1>描述:{{ $store.getters["user1/description"] }}</h1>
    <button @click="changeAge1">修改年龄</button>

在这里插入图片描述

模块中辅助函数的写法

<template>
<!-- 命名空间:辅助函数的写法 -->
    <h1>用户名:{{ user1.username }}</h1>
    <h1>年龄:{{ user1.age }}</h1>
    <h1>描述:{{ description }}</h1>
    <button @click=" setAge">异步修改年龄</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
  computed: {
    ...mapState(["user1"]),
    ...mapGetters("user1", ["description"]),
    ...mapMutations('user1',['setAge'])
  },
  
  methods: {
    ...mapActions("user1", ["asyncSetAge"]),
  },
};
</script>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值