Vue3脚手架笔记

发布时间:2024年01月23日

基本语法

1.1、初时Vue

1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
3.root容器里的代码被称为【Vue模板】;
4.Vue实例和容器是一一对应的;
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
注意区分:js表达式 和 js代码(语句)
	1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
		(1). a
		(2). a+b
		(3). demo(1)
		(4). x === y ? 'a' : 'b'
	2.js代码(语句)
		(1). if(){}
		(2). for(){}

1.2、插值语法{{}}

Vue模板语法有2大类
1.插值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
** 2.指令语法:**
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-???,此处我们只是拿v-bind举个例子。

1.3、绑定属性

Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。

<!-- 普通写法 -->
  单向数据绑定:<input type="text" v-bind:value="name"><br/>
  双向数据绑定:<input type="text" v-model:value="name"><br/>

<!-- 简写 -->
  单向数据绑定:<input type="text" :value="name"><br/>
  双向数据绑定:<input type="text" v-model="name"><br/>

1.3.1绑定样式

<template>
  <div>
    <!--绑定样式-->
    <div :style="['font-size:50px','color:red']">box</div>
    <div :style="[fontSize,bgColor]">box</div>
    <hr>
    <!--绑定类-->
    <!--    <div class="one" :class="'two'">aaaaaaaa</div>-->
    <div class="one" :class="two">aaaaaaaa</div>
    <!--    <div class="one" :class="['one','two']">aaaaaaaa</div>-->
    <!--数组方式-->
    <div class="one" :class="[one,two]">元素为变量</div>
    <div class="one" :class="boxStyle">数组为变量</div>
    <hr>
    <!--对象方式  {类名:真假值}  真则添加 假则不添加-->
    <div :class="{one:isone,two:istwo}">{类名:真假值} 真则添加 假则不添加</div>
    <div :class="{three}">键值相同可简写</div><!--键值相同可简写-->
    <!--函数返回值方式-->
    <div :class="getStyleObj()">函数返回对象</div>
    <div :class="getStyleArr()">函数返回数组</div>
  </div>
</template>
<script>
/*
* 单向绑定 v-bind 简写  :
*
* */
export default {
  name: 'App',
  data() {
    return {
      size: 100,
      fontSize: 'font-size:50px',
      bgColor: 'background-color:blue',
      two: 'two',
      one: 'one ',
      boxStyle: ['one', 'two'],
      isone: false,
      istwo: true,
      three: true,
    };
  },
  methods: {
    getStyleArr() {
      return [this.one, this.two];
    },
    getStyleObj() {
      return { one: this.isone, two: this.istwo };
    },
  },
};
</script>

1.4、计算属性

1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
(1)计算属性最终会出现在vm上,直接读取使用即可。
(2)如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。

computed:{
				fullName:{
					//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
					//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
					get(){
						console.log('get被调用了')
						// console.log(this) //此处的this是vm
						return this.firstName + '-' + this.lastName
					},
					//set什么时候调用? 当fullName被修改时。
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				}
			}

1.5、事件监听

在前端开发中,需要经常和用户交互
绑定事件监听器指令:v-on
缩写: @ (语法糖)
参数: $event
v-on事件修饰符号
–.stop 阻止事件冒泡
–.self 当事件在该元素本身触发时才触发事件
–.capture 添加事件侦听器是,使用事件捕获模式
–.prevent 阻止默认事件
–.once 事件只触发一次

1.6、条件分支指令v-if和v-show

1.v-if
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
适用于:切换频率较低的场景。
** 特点:不展示的DOM元素直接被移除。**
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

2.v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(display:none)

3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

1.7、循环遍历指令v-for

v-for指令:
1.用于展示列表数据
2.语法:v-for=“(item, index) in xxx” :key=“yyy”
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

	<!-- 遍历数组 -->
			<h2>人员列表(遍历数组)</h2>
			<ul>
				<li v-for="(p,index) of persons" :key="index">
					{{p.name}}-{{p.age}}
				</li>
			</ul>

			<!-- 遍历对象 -->
			<h2>汽车信息(遍历对象)</h2>
			<ul>
				<li v-for="(value,k) of car" :key="k">
					{{k}}-{{value}}
				</li>
			</ul>

			<!-- 遍历字符串 -->
			<h2>测试遍历字符串(用得少)</h2>
			<ul>
				<li v-for="(char,index) of str" :key="index">
					{{char}}-{{index}}
				</li>
			</ul>
			
			<!-- 遍历指定次数 -->
			<h2>测试遍历指定次数(用得少)</h2>
			<ul>
				<li v-for="(number,index) of 5" :key="index">
					{{index}}-{{number}}
				</li>
			</ul>

补充:key的原理

:::info
面试题:react、vue中的key有什么作用?(key的内部原理)
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

2.对比规则:
      (1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
            ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
            ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

      (2).旧虚拟DOM中未找到与新虚拟DOM相同的key
            创建新的真实DOM,随后渲染到到页面。
            
3. 用index作为key可能会引发的问题:
          1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
                  会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

          2. 如果结构中还包含输入类的DOM:
                  会产生错误DOM更新 ==> 界面有问题。

4. 开发中如何选择key?:
          1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
          2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
            使用index作为key是没有问题的。

:::

1.8、v-model双向绑定

v-model的修饰符号:
.lazy 懒加载修饰符
.number 修饰符让其转换为 number 类型
.trim修饰符可以自动过滤掉输入框的首尾空格

1.9、v-model在表单中的应用

1.9.1、单选框

    1、使用v-model 可以代替name 变量相同则代表同组
    2、单选框状态发生改变时 会把value中的数据传到 v-model绑定的变量中
    3、初始选项不必再使用checked ,直接给变量赋初值即可
<input type="radio" name="sex" value="女">-->
  <input type="radio" value="男" v-model="sex"><input type="radio" value="女" v-model="sex"><br>{{sex}}


data() {
    return {
      msg: 'this is a test',
      sex:'男',
      isRead:false,
      hobby:[],
      language:'vue',
      languages:'vue',
    }

1.9.2、多选框

1、当只需要一个复选框为真假值判断的时候,v-model传递一个布尔值,会自动根据选种情况来改变 变量值的真或假
2、当需要多个复选框同组使用时 , 需要使用数组变量接收 ,会把选中项的value值存到数组中
使用v-model 可以代替name 变量相同则代表同组

<input type="checkbox" v-model="isRead">我已阅读协议{{isRead}}
<br>
  <input type="checkbox" v-model="hobby" value="smoke">抽烟
  <input type="checkbox" v-model="hobby" value="drink">喝酒
  <input type="checkbox" v-model="hobby" value="hotHead">烫头
  <br>
{{hobby}}


data() {
    return {
      msg: 'this is a test',
      sex:'男',
      isRead:false,
      hobby:[],
      language:'vue',
      languages:'vue',
    }

1.9.3、下拉列表

1、单选时
1)v-model绑定在select标签上 可以代替name的功能
2)使用一个字符串接受选中value值
3)设置初始选项时可以将目标选项的value赋给字符串变量
2、多选时 multiple
会自动将变量转成数组类型,并将选中选项的value值存到数组中

<select v-model="language">
  <option value="java">java</option>
  <option value="php">php</option>
  <option value="vue">vue</option>
  <option value="python">python</option>
  </select>
{{language}}
<br>
  <select v-model="languages" multiple>
  <option value="java">java</option>
  <option value="php">php</option>
  <option value="vue">vue</option>
  <option value="python">python</option>
  </select>
{{languages}}

data() {
    return {
      msg: 'this is a test',
      sex:'男',
      isRead:false,
      hobby:[],
      language:'vue',
      languages:'vue',
    }

组件化开发

  • 组件化是Vue的精髓,Vue开发就是由一个一个的组件构成的。
  • 组件的分类:
    • 页面级组件
    • 业务上可复用的基础组件
    • 与业务无关的独立功能组件
  • 组件开发三要素(prop,自定义事件,slot)
    • prop用于定义组件的属性。
    • 自定义事件用于触发组件的事件。
    • slot用于组件功能的扩展。
  • 组件设计需要考虑的问题
    • 可扩展性强
    • 组件中方法函数的抽离,便于复用,适用程度高。
    • 文档清楚详细
    • 颗粒度合适,适度抽象
    • 功能尽可能单一,代码行数适中

2.1、父子组件之间的通信

2.1.1、父组件向子组件传数据 父=>子

props配置项

  1. 功能:让组件接收外部传过来的数据 , 接收到后用法和data中数据一样 (父 ==> 子)
  2. 传递数据:
  3. 接收数据:
    1. 第一种方式(只接收):props:[‘name’]
    2. 第二种方式(限制类型):props:{name:String}
    3. 第三种方式(限制类型、限制必要性、指定默认值):
      :::info
      props:{
      name:{
      type:String, //类型
      required:true, //必要性 不传则警告
      default:‘老王’ //默认值
      }
      }
      :::
      _ 备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,_
      _ 若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。_
//父组件
<my-conn :article="article"></my-conn>

  
//子组件
<li v-for="item in article">{{item}}</li>

export default {
  name: "MyConn",
  props:{
    article:{
      type:Array,
    }
  }
}

2.1.2、子组件向父组件传数据 子=>父

**通过自定义事件 e m i t ( ) 和事件监听实现 ? ? 子组件通过使用 t h i s . emit()和事件监听实现** 子组件通过使用this. emit()和事件监听实现??子组件通过使用this.emit(‘自定义事件名称’,传递参数data)
父组件通过在组件标签上使用<子组件 @自定义事件名称=“方法fun”></子组件>
fun(子组件传递的参数data){}

//子组件 my-conn
<button @click="changeNum(2)">++++</button>

 methods:{
    changeNum(n){
      this.$emit("myCountEvent",n)
    }
  }

//父组件
<my-conn @myCountEvent="myDemo"></my-conn>
 methods:{
   myDemo(data){
      this.count += data
    }
  }

2.2父子组件之间的访问方式

2.2.1、子组件访问父组件:

可以通过$parent获取父组件中的属性和方法,可连续调用访问多层
如果访问跟组件可直接调用$root方法

2.2.2、父组件访问子组件:

在Vue2中可以使用$children 获取一个子组件数组,Vue3删除了该方法
可以先使用 ref属性标记子组件 (类似id属性)  ref="xxx"
    再调用 $refs.xxx  获取子组件

2.3、插槽

  1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,
    适用于父组件 ===> 子组件。
  2. 分类:默认插槽、具名插槽、作用域插槽

2.3.1、默认插槽

<!--  默认插槽  ==>父组件 -->
  <MyBar>
  	<button>默认插槽--提交</button>
  </MyBar>

<!--  默认插槽 ==>子组件-->
  <slot>默认值</slot>

2.3.2、具名插槽

:::info
需要使用包裹内容
template中设置属性
1. v-slot:子组件中插槽name值 简写 #子组件中插槽name值
2. Vue2中还可使用 slot=“子组件中插槽name值” Vue3已删除
:::

<!--  具名插槽  ==>父组件-->
<MyBar>
    <template v-slot:btn>
      <button>具名插槽--提交</button>
    </template>
    <template #one>
      <a href="">具名插槽--one</a>
    </template>
    <template #two>
      <a href="">具名插槽--two</a>
    </template>
  </MyBar>

<!--  具名插槽 ==>子组件-->
  <slot name="btn">默认值1</slot>
  <br>
  <slot name="one">默认值2</slot>
  <br>
  <slot name="two">默认值3</slot>
  <br>

2.3.3、作用域插槽

:::info
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
(userinfo和school数据在子组件Mybar中,但使用数据所遍历出来的结构由父组件MySidebar决定)
使用方法 :
v-slot:子组件中插槽的name值=“自定义对象” ,子组件传的所有数据都会存到自定义的对象中
简写:#子组件中插槽的name值=“自定义对象”
:::

<!--作用域插槽  ==>父组件 -->
<MyBar>
    <!--    <template v-slot:user="user">-->
    <template #user="hello">
    <p>作用域插槽--{{hello.userinfo.name}}-{{hello.userinfo.age}}--{{hello.userinfo.sex}}</p>
    <p v-for="item in hello.school">{{item}}</p>
    </template>
</MyBar>

 <!--  作用域插槽 ==>子组件-->
  <slot name="user" :userinfo="userinfo" :school="school"></slot>

data(){
    return{
    title:"this is a title",
      userinfo:{name:'张三',age:24,sex:'男'},
      school:['融职教育','清华大学','北京大学','麻省理工']
    }
  }

2.4、Vue中组件的生命周期函数

  • (1)初始化显示
    • beforeCreate()
    • created()
    • beforeMount()
    • mounted()
  • (2)更新状态: this.xxx = value
    • beforeUpdate()
    • updated()
  • (3)销毁 vue 实例: vm.$destory()
    Vue2
    • beforeDestory()
    • destoryed()

Vue3

  • beforeUnmount()

  • unmounted()

  • (4) nextTick

    • 语法:this.$nextTick(回调函数)
    • 作用:在下一次 DOM 更新结束后执行其指定的回调。
    • 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
  • (5)Vue-router的生命周期钩子
    :::info



    :::

      1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
      1. 具体名字:

activated路由组件被激活时触发。
? ? ? ? ? ?deactivated路由组件失活时触发。

2.5、Vue网络请求axios

import axios from "axios";

const server = axios.create({
  baseURL: 'https://api.shop.eduwork.cn',
  timeout: 10000,
  headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
//请求拦截器
server.interceptors.request.use(
  config => {
    console.log('-------------------请求拦截器----------------------')
    config.headers.Authorization = `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5zaG9wLmVkdXdvcmsuY24vYXBpL2F1dGgvbG9naW4iLCJpYXQiOjE2ODE4MTk0OTQsImV4cCI6MTY4MjE3OTQ5NCwibmJmIjoxNjgxODE5NDk0LCJqdGkiOiJ4clZ6c2ZVelpySVJnYk1wIiwic3ViIjoiODk0MiIsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.vsKQvw9m0HhWfUbzJuOvBvWVK4BnAxi-vOSNCkBwJoQ`
    return config
  },
  err => {
    return Promise.reject(error)
  }
)
//响应拦截器
server.interceptors.response.use(
  resp => {
    console.log('-------------------响应拦截器----------------------')
    return resp
  },
  err => {
    return Promise.reject(err)
  }
)

export function get(url) {
  return server.get(url)
}

export function getParams(url, params) {
  return server.get(url, {params})
}

export function post(url, params) {
  return server.post(url, params)
}

export function put(url, params) {
  return server.put(url, params)
}

export function del(url, params) {
  return server.delete(url, params)
}

Vue Router 路由

3.1、基本使用

  1. 安装vue-router,命令:npm i vue-router
  2. 应用插件:Vue.use(VueRouter)
import router from './router'
createApp(App).use(router).mount('#app')
  1. 配置:
//引入路由的创建方法和模式
import {createRouter,createWebHistory} from 'vue-router'

//引入组件
import About from "@/view/About";
import Home from "@/view/Home";
import User from "@/view/User";

// 声明变量
const routes = [
  {
    path:'/',
    name:'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },
  {
    path: '/user',
    name: 'User',
    component: User
  }
]
//创建路由
const router = createRouter({
  history:createWebHistory(process.env.BASE_URL), //历史模式
  // routes:routes,
  routes
})

export default router
  1. 实现路由切换

	<router-link to="/">首页</router-link> |
	<router-link active-class="active" to="/about">关于我们</router-link> |
	<router-link to="/user">个人中心</router-link>
//active-class="active"  当跳转到当前路由时添加active类样式
  1. 指定显示位置
    :::info

    :::

3.2 几个注意点

  1. 路由组件通常存放在view文件夹,一般组件通常存放在components文件夹。
  2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
  3. 每个组件都有自己的$route属性,里面存储着自己的路由信息。
  4. 整个应用只有一个router,可以通过组件的$router属性获取到。

3.3 路由模式切换和懒加载

路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置
Vue-Router在切换页面时是没有重新进行请求的,使用起来就好像页面是有状态的一样
借助了浏览器的History API来实现的,这样可以使得页面跳转而不刷新,页面的状态就被维持在浏览器中
vue-router中默认使用的是hash模式,也就是会出现如URL:‘localhost:8080/#/’ URL中带有#号
有三种模式
Hash: 使用URL的hash值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器。
History: 以来HTML5 History API 和服务器配置。
Abstract: 支持所有javascript运行模式。如果发现没有浏览器的API,路由会自动强制进入这个模式。

引入路由
:::info
//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from ‘vue-router’
:::
创建路由

const router = createRouter({
	//设计模式
	history:createWebHistory(process.env.BASE_URL), //历史模式
	// history:createWebHashHistory(process.env.BASE_URL),//哈希模式
	//定义路由组件
	/*
	 routes:[
		{
			path:'/',
			name:'Home',
			component: Home
		},
		]
 */
		//外部引入变量方式
		// routes:routes,
	  //简写
		routes
})

引入组件的方式
方式一:普通方式:
打包时会将所有路由全部打包到一个js文件中,并加载全部组件

//引入组件
import Home from "@/view/Home";
import About from "@/view/About";
import User from "@/view/User";
const routes = [
    {
        path:'/',
        name:'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: About
    },

    {
        path: '/user',
        name: 'User',
        component:User
    }
]

方式二:懒加载:
通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) — 加载速度快

const routes = [
    {
        path:'/',
        name:'Home',
        component: ()=>import('../view/Home')
    },
    {
        path: '/about',
        name: 'About',
        component: About
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        //通过下面方法引入组件,会在打包时会打包成多个js文件,访问哪个路由加载哪个js文件(懒加载) --- 加载速度快
       /* component: () => import(/!* webpackChunkName: "about" *!/ '../views/About.vue')*/
        /*component: ()=>{return import('../view/About')}*/
        component: ()=>import('../view/About')

    },

    {
        path: '/user',
        name: 'User',
        component:()=>import('../view/User')
    }
]

拆分写法

//引入路由的创建方法和模式
import {createRouter,createWebHistory,createWebHashHistory} from 'vue-router'

const Home = ()=> import('../view/Home')
const About = ()=> import('../view/About')
const User = ()=> import('../view/User')
// 声明变量
const routes = [
    {
        path:'/',
        name:'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: About

    },
    {
        path: '/user',
        name: 'User',
        component:User
    }
]
//创建路由
const router = createRouter({
    //设计模式
    history:createWebHistory(process.env.BASE_URL), //历史模式
    // history:createWebHashHistory(process.env.BASE_URL),//哈希模式
    
    // routes:routes,
    routes
})

export default router

使用路由:在入口js文件中

import {createApp} from 'vue'
import App from './App'
import router from './router'

createApp(App).use(router).mount('#app')

3.4 自定义标签

标签在打包时会编译成a标签,如果想要自定义其他标签的话在Vue3中需要通过以下方法:

<router-link to="/about" custom v-slot="{navigate}">
  <button @click="navigate" @keypress.enter="navigate" role="link">关于我们</button>
</router-link>
            //或
  // 通过在全局路由追加历史记录实现
<button @click="$router.push('/user')" :class="{active:$route.path ==='/user'}">个人中心</button>
$router 表示全局路由
$route 表示当前路由

3.5 <router-link>的replace属性

  1. 作用:控制路由跳转时操作浏览器历史记录的模式
  2. 浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
  3. 如何开启replace模式:<router-link replace .......>News</router-link>

3.6 嵌套路由

  1. 配置路由规则,使用children配置项:
const routes = [
    {
        path:'/',
        name:'Home',
        component: Home
    },
    {
        path: '/user',
        name: 'User',
        component:User,
        //   /user/order
        children: [
            {
                path:'',   //默认页面
                component:MyOrder,
            },
            {
                path:'order',   //此处一定不要写:/order
                name:'MyOrder',
                component:MyOrder,
            },
            {
                path:'setting',   //此处一定不要写:/setting
                name:'MySetting',
                component:MySetting,
            },
            {
                path:'page/:id',
                name:'MyPage',
                component:MyPage,
            },

        ]
    }
]
  1. 跳转**(要写完整路径)**
<router-link to="/user/order">我的订单</router-link>
  <br>
<router-link to="/user/setting">个人设置</router-link>

3.7 参数传递

3.7.1 query参数

  1. 传递参数
<!-- 跳转并携带query参数,to的字符串写法 -->
  <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>

  <!-- 跳转并携带query参数,to的对象写法 -->
  <router-link 
    :to="{
      path:'/home/message/detail',
      query:{
      id:666,
      title:'你好'
   	 }
		}"
	>跳转</router-link>
  1. 接收参数:
$route.query.id
$route.query.title

3.7.2 命名路由

  1. 作用:可以简化路由的跳转。
  2. 如何使用
  3. 给路由命名:
{
	path:'/demo',
	component:Demo,
	children:[
		{
			path:'test',
			component:Test,
			children:[
				{
          name:'hello' //给路由命名
					path:'welcome',
					component:Hello,
				}
			]
		}
	]
}
  1. 简化跳转:
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>

<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link 
	:to="{
		name:'hello',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

3.7.3 params参数

  1. 配置路由,声明接收params参数
{
  path:'/home',
    component:Home,
    children:[
    {
      path:'news',
      component:News
    },
    {
      component:Message,
      children:[
        {
          name:'xiangqing',
          path:'detail/:id/:title', //使用占位符声明接收params参数
          component:Detail
        }
      ]
    }
  ]
}
  1. 传递参数
<!-- 跳转并携带params参数,to的字符串写法 -->
    <router-link :to="/home/message/detail/666/你好">跳转</router-link>

    <!-- 跳转并携带params参数,to的对象写法 -->
    <router-link 
        :to="{
            name:'xiangqing',
            params:{
            id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>

特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

  1. 接收参数:
$route.params.id
$route.params.title

3.7.4路由的props配置

作用:让路由组件更方便的收到参数
{
  name:'xiangqing',
    path:'detail/:id',
    component:Detail,

    //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
    // props:{a:900}

    //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
    // props:true

    //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
    props(route){
    return {
      id:route.query.id,
      title:route.query.title
    }
  }
}
<ul>
      <li>消息编号:{{id}}</li>
      <li>消息标题:{{title}}</li>
</ul>


<script>
    export default {
        name:'Detail',
        props:['id','title'],
      }
</script>

3.8 编程式路由导航

  1. 作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
  2. 具体编码:
//$router的两个API
this.$router.push({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})

this.$router.replace({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})
this.$router.forward() //前进;
this.$router.back() //后退
this.$router.go() //可前进也可后退

3.9 重定向和别名

重定向:跳转到当前路由时,若此路由被重定向,则跳转到重定向指定的路由
redirect{name:‘路由name’}

别名:别
名是 **路径 ,**通过别名也可代替path中的路径
单个别名:alias: ‘/a’
多个别名:alias: [‘/a’ ,‘/b’,‘/c’]
注意:原路径有params参数 别名也需要写
:::info
{
path:‘page/:id’,
name:‘MyPage’,
alias:[‘p/:id’],
}
:::

const routes = [
  {
    path:'/',
    name:'HomeRoot',
    component: Home
  },
  {
    path:'/home',
    name:'Home',
    //重定向
    // redirect:'/',  //路径
    redirect:{name:'HomeRoot'},  //名字
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    //单个别名
    // alias:'/a',
    //多个别名
    alias:['/a','/b','/c'],
    //原路径有params参数 别名也需要写
    component: About
  },

  {
    path: '/user',
    name: 'User',
    component:User,
    //   /user/order
    children: [
      {
        path:'page/:id',
        name:'MyPage',
        //原路径有params参数 别名也需要写
        alias:['p/:id'],
        /* redirect:to=>{
                    //to  => $route
                  return {path:'article',query:{name:'zhangsan',age:to.params.id}}
                },*/
        //缩写 to=>({})
        component:MyPage,
      },
    ]
  }
]

3.10 路由守卫

  1. 作用:对路由进行权限控制
  2. 分类:全局守卫、独享守卫、组件内守卫

全局守卫:

//全局路由守卫
//全局前置路由守卫
/*Vue2中 有三个参数 :to :即将进入的路由
                 from 要离开的路由,
                 next (放行)
Vue3中  可以有两个参数:to ,from,next(可选) ,是否放行取决于返回值,假则禁止放行,真或不写则放行*/
router.beforeEach((to,from)=>{
  document.title = to.meta.title;
  // return false
})
//全局后置路由守卫
router.afterEach((to,from)=>{
  // console.log('afterEach',to,from)
  if(to.meta.title){
    document.title = to.meta.title //修改网页的title
  }else{
    document.title = 'vue_test'
  }
})

独享守卫:

{
  path:'setting',   //此处一定不要写:/setting
    name:'MySetting',
    beforeEnter(to,from){
    console.log('beforeEnter',to,from)
    if(localStorage.getItem('school') === 'rongzhi'){
      return true
    }else{
      alert('暂无权限查看')
      return false
    }
  },
  component:MySetting,
},

组件内守卫: 在组件中使用

进入守卫:通过路由规则,进入该组件时被调用
:::info
beforeRouteEnter (to, from) {
},
:::

离开守卫:通过路由规则,离开该组件时被调用
:::info
beforeRouteLeave (to, from) {
}
:::

3.11 keep-alive和vue-router结合使用

  1. 作用:让不展示的路由组件保持挂载,不被销毁,保存在缓存中。
  2. 具体编码:

Vue3中:

<router-view v-slot="{Component}">
  <transition>
    <keep-alive>
      <component :is="Component"/>
    </keep-alive>
  </transition>
</router-view>

Vue2中:

<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>
两个新的生命周期钩子
  1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  2. 具体名字:
  3. activated路由组件被激活时触发。
  4. deactivated路由组件失活时触发。

VueX

概念

	在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

何时使用?

	多个组件需要共享数据时

基本使用

  1. 初始化数据、配置actions、配置mutations,操作文件store.js
export default createStore({
  state: {
    num:0,
    dnum:0,
  },
  getters: {
  },
  mutations: {
    mutAdd(state){
      state.dnum ++
    },
    mutSub(state){
      state.dnum --
    },
    //接收一个参数,参数可以使任意类型
    mutAdd2(state,count){
      state.dnum +=count
    },
    mutSub2(state,count){
      state.dnum -=count
    },
    //接收多个参数
    //将多个参数存在一个对象中
    mutAdd3(state,payload){
      state.dnum +=payload.count+payload.num
    },
    mutSub3(state,payload){
      state.dnum -=payload.count+payload.num
    },
    //对象写法接收
    mutSub4(state,p){
      state.dnum -=p.payload.count+p.payload.num
    },

  },
  actions: {
  },
  modules: {
  }
})
  1. 组件中读取vuex中的数据:$store.state.sum
  2. 组件中修改vuex中的数据:$store.dispatch(‘action中的方法名’,数据) 或 $store.commit(‘mutations中的方法名’,数据)

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

搭建vuex环境

  1. 创建文件:src/store/index.js
//引入Vuex
import { createStore } from 'vuex'
//暴露
export default createStore({
  //准备state对象——保存具体的数据
  state: {
    num:0,
  },
  //VueX中的计算属性
  getters: {
  },
  //准备mutations对象——修改state中的数据
  mutations: {
  },
  //准备actions对象——响应组件中用户的动作
  actions: {
  },
  //模块化
  modules: {
  }
})
  1. 在main.js中创建vm时传入store配置项
import store from './store'
createApp(App).use(store).use(router).mount('#app')

mutations传参问题

mutations中的方法只能接受两个参数
第一个参数:当前 state
第二个参数:接收到的数据
可以接收任何类型的数据,如果要传递多个数据,则需要将数据放到一个对象中进行传递
组件读取mutations中方法的方式:this.$store.commit(‘方法名’, 参数)

mutations: {
  mutAdd(state){
    state.dnum ++
  },
  mutSub(state){
    state.dnum --
  },
  //接收一个参数,参数可以使任意类型
  mutAdd2(state,count){
    state.dnum +=count
  },
  mutSub2(state,count){
    state.dnum -=count
  },
  //接收多个参数
  //将多个参数存在一个对象中
  mutAdd3(state,payload){
    state.dnum +=payload.count+payload.num
  },
  mutSub3(state,payload){
    state.dnum -=payload.count+payload.num
  },
  //对象写法接收
  mutSub4(state,p){
    state.dnum -=p.payload.count+p.payload.num
  },

},

调用mutations中的方法

subMut() {
  //调用Vuex中mutation中的方法
  //this.$store.commit.('方法名')
  this.$store.commit('mutSub')
},
subTwo() {
  let count = 2
  this.$store.commit('mutSub2', count)
},
addThree() {
  /*let count = 2
  let num = 1*/
  let payload = {
    count: 2,
    num: 1
  }
  //commit只有两个参数,如果想传多个参数则需要放到一个对象里
  this.$store.commit('mutAdd3', payload)
},
subThree() {
  let payload={
    count:2,
    num:1
  }
  // this.$store.commit('mutSub3',payload)
  //  对象写法
  this.$store.commit({
    type: 'mutSub4',  //方法名
    /*payload: {
      count: 2,
      num: 1
    }*/
    payload
  })
}

vuex中的计算属性getters应用

  1. 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
  2. 组件中读取数据:$store.getters.方法名
    :::info
    getters中定义的方法有两个参数
    第一个参数就是state
    第二个getters
    如果想要传参数的话需要通过返回回调函数,并将要传的参数作为回调函数的参数
    :::
vxNum(state) {
    return state.num * state.num
},
booksPrice(state) {
    let priceSum;
    priceSum = state.books.reduce((s, n) => {
        return s + n.price
    }, 0)
    return priceSum
},
booksGet(state) {
 return  state.books.filter(book=>{
    return book.price >30
  })
},
booksGet1(state,getters) {
  //参入以回调函数参数形式传入
  return function (price) {
    return  state.books.filter(book=>{
      return book.price > price
    })
  }
  /*return  state.books.filter(book=>{
        return book.price >30
    })*/
},
  
//组件中
<h2>getter中的计算属性</h2>
<h3>{{$store.getters.vxNum}}</h3>
<h1>全部图书的总价</h1>
<h2>{{$store.getters.booksPrice}}</h2>
<h1>价格大于30的数的图书</h1>
<h2>{{$store.getters.booksGet}}</h2>
<h1>价格大于30的数的图书总价</h1>
<h2>{{$store.getters.booksPrice1}}</h2>
<h1>参数传递:价格大于20的数的图书</h1>
<h2>{{$store.getters.booksGet1(20)}}</h2>

actions异步处理操作

:::info
参数:第一个参数 context 代表上下文
相当于组件中的 this. s t o r e 第二个参数和 m u t a t i o n s 中方法的第二个参数一样 , 负责接收数据 : : : 组件中获取 a c t i o n s 中方法的方式: ? ? t h i s . store 第二个参数和mutations中方法的第二个参数一样,负责接收数据 ::: 组件中获取actions中方法的方式:**this. store第二个参数和mutations中方法的第二个参数一样,负责接收数据:::组件中获取actions中方法的方式:??this.store.dispatch(‘方法名’,参数)**

demo(context){
  setTimeout(()=>{
    // context.state.num = 99;
    context.commit('mutAdd')
  },3000)
},

context中的方法: 可以使用解构赋值选择调用
1.commit
2.dispatch
3.getters
4.state
5.rootGetters 获取根中的getters
6.rootState 获取根中的state

fun2({state,commit,getters},payload){
  // const {state,commit} = context
  setTimeout(()=>{
    state.num=99+payload.num1
    commit('cnum')
  },100)
}

注意:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写****commit

module模块划分

modules: {
  //拆分成多个模块
  //普通形式
  user:{
    state:{

    },
    getters:{},
    mutations:{},
    actions:{}
  },
  //声明调用分开
  article:article,
    //简写
    cart,
    goods,
}
const article = {
  //在模块中state状态需要放在函数里面返回  类似 data(){return{}}
  state:()=>({
    name:'lmonkey',
    slogen:'abc'
  }),
  getters:{
    fullname(state){
      return state.name+state.slogen
    },
    fullname2(state,getters){
      //本模块中的getters
      return getters.fullname+"222222"
    },
    fullname3(state,getters,rootState){
      //rootState 根
      //调用根中的state
      return getters.fullname2+rootState.books[0].name
    }
  },
  mutations:{
    setname(state,payload){
      state.name = payload.name
    }
  },
  actions:{
    demosome(context,payload){
      /* context中的方法: 可以使用解构赋值选择调用
                1.commit
                2.dispatch
                3.getters
                4.state
                5.rootGetters   获取根中的getters
                6.rootState     获取根中的state
            */
      // console.log(context)
      setTimeout(()=>{
        context.commit('setname',payload)
      },2000)
    }
  }
}
const cart = {
  state:{

  },
  getters:{},
  mutations:{},
  actions:{}
}
const goods = {
  state:{

  },
  getters:{},
  mutations:{},
  actions:{}
}

如果在模块中想要获取根中的数据
在getters中,可以直接使用第三个参数rootState,获取根中的状态
在actions中,可以使用context中的rootState或rootGetters

组合式API

https://vue3js.cn/vue-composition-api/

文章来源:https://blog.csdn.net/shiqing4387/article/details/135775832
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。