首页 > 其他分享 >vue3入门教程,一站学会全套vue!

vue3入门教程,一站学会全套vue!

时间:2024-10-24 16:49:29浏览次数:3  
标签:vue const app 入门教程 vue3 组件 import 路由

vue3

vue3作为前端重要的框架,学会vue可以让你更加了解前端。本博客致力于让你一站学会vue3的全部内容,从小白到高手。
全是干货,准备好了吗?

文章目录

创建工程

使用vite创建

vite 是新一代前端构建工具,官网地址:https://vitejs.cn

## 1.创建命令
npm create vue@latest

## 2.具体配置
## 配置项目名称
√ Project name: vue3_test
## 是否添加TypeScript支持
√ Add TypeScript?  Yes
## 是否添加JSX支持
√ Add JSX Support?  No
## 是否添加路由环境
√ Add Vue Router for Single Page Application development?  No
## 是否添加pinia环境
√ Add Pinia for state management?  No
## 是否添加单元测试
√ Add Vitest for Unit Testing?  No
## 是否添加端到端测试方案
√ Add an End-to-End Testing Solution? » No
## 是否添加ESLint语法检查
√ Add ESLint for code quality?  Yes
## 是否添加Prettiert代码格式化
√ Add Prettier for code formatting?  No

文档结构

├── node_modules 
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── component: 存放组件
│   │   └── HelloWorld.vue
│	│── pages:存放路由组件
│	│── router:存放路由配置
│   │   └── index.js:默认路由入口文件
│   │── utils:封装自己或者第三方的工具
│   │── store:使用pinia插件时,存储全局数据
│   │── App.vue: 汇总所有组件
│   │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件 
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件
├── vite.config.js: 脚手架配置

核心语法

模板语法

插值语法

文本插入

使用{{data_attribute}}插入数据

原始HTML插入(可能会出现安全问题)

使用v-html指令

<template>
	<div v-html="rawhtml"></div>//rawhtml中的内容会被插入到div标签里
</template>
指令语法
无参指令

控制元素的显示与隐藏

<template>
	<div v-if="divif"></div>//divif=true展示
	<div v-show="divshow"></div>//divshow=true展示
//v-if是和dom元素的有无有关,v-show和dom元素的display属性有关
</template>
有参指令

单向数据绑定v-bind (简写:)

<template>
	<div v-bind:id="dynamicId"></div>
	//简写
	<div :id="dynamicId"></div>
	//同名简写:id=id
	<div :id></div>
	//绑定多组数据
	<div v-bind="objectOfAttrs"></div>
</template>

双向数据绑定

<input v-modle:value="x"/>
//简写
<input v-modle="x"/>

事件监听

<div v-on:click="dosomething"/>
//简写
<div @click="dosomething"/>
//在dosomething中默认第一个参数会传入event事件对象。

事件对象$event: 是包含事件相关信息的对象(pageXpageYtargetkeyCode

​ 事件修饰符

​ prevent:阻止事件默认行为

​ stop:阻止事件冒泡行为

<div @click.prevent="dosomething"/>

循环指令

<div v-for="(value ,key)in items" :key="key">
  {{ value }}
</div>
//v-for所在的元素及其子元素内都能使用遍历的内容。
//结果就是v-for所在元素及其子元素都生成了遍历次数的真实dom元素

其他指令

v-if : 如果为 true, 当前标签才会输出到页面

v-else: 如果为 false, 当前标签才会输出到页面

v-cloak : 防止闪现, 与 css 配合: [v-cloak] { display:none}

自定义指令

参考:https://cn.vuejs.org/guide/reusability/custom-directives.html

setup

setup函数

组件中所用到的:数据、方法、计算属性、监视…等都写在里面,但只有返回之后才能在模板里直接使用。setup函数中访问this是undefined。

返回值

·返回一个对象中的:属性、方法等,都可以在模板中直接使用。

·返回一个函数,则可以自定义渲染页面。

setup(){
	return () => "hello world!" //组件所渲染的部分展示hello world!
}
setup语法糖
<script lang="ts">
  export default {
    name:'Name',
  }
</script>

<!-- 下面的写法是setup语法糖 -->
<script setup>
  console.log(this) //undefined
  let name = 'wuhu'
</script>

组件的name属性需要在script标签中单独定义,显得不是那么灵活。

用vite中的插件可以简化代码

(插件的使用

第一步 安装插件 npm i vite-plugin-vue-setup-extend -D

第二步 在vite.config.js中配置插件

import { defineConfig } from 'vite'
import VUeSetupExtend from 'vite-plugin-vue-setup-extend'

export default defineConfig({
	plugins:[
		VueSetupExtend()
	]
})

配置好后代码可简化为只写一个setup标签

<script setup name="Name">
</script>

响应式数据

ref

定义基本类型的响应式数据

语法:let xxx = ref(初始值)

返回值:返回一个RefImpl的实例对象,ref对象的value属性是响应式的。

使用数据:

​ ·js这种操作数据需要:xxx.value,但模板中直接使用即可。

​ ·xxx不是响应式的,xxx.value是响应式的。

定义对象类型

语法:let xxx = ref(源对象)

使用数据:

​ ·在js中,xxx.value.属性

​ ·在模板中,直接使用即可

reactive

只能定义对象类型的响应式数据

语法:let xxx = reactive(源对象)

返回值:一个Proxy的实例对象,简称:响应式对象。

使用数据:直接使用即可

注意:

​ ·rective重新分配一个新的对象,会失去响应式(可以使用Object.assign整体替换)

​ ·若需要一个层次较深的响应式对象,推荐使用reactive

toRef & toRefs

将响应式对象中的属性,转换为ref对象。

<script setup name="Person">
  import {ref,reactive,toRefs,toRef} from 'vue'

  // 数据
  let person = reactive({name:'wuhu', age:18, gender:'男'})
	
  // 通过toRef将person对象中的gender属性取出,且依然保持响应式的能力
  let age = toRef(person,'age')
  
  // 通过toRefs将person对象中的n个属性批量取出,且依然保持响应式的能力
  let {name,gender} =  toRefs(person)
</script>

计算属性computed

通过响应式数据计算得到新的属性。当原响应式对象的值发生改变时,会重新计算并更新。

语法:

只读: let xxx = computed( ()=>{dosomething and return } )

读并且修改: let xxx = computed({get(){},set(){} })

<script setup lang="ts" name="App">
  import {ref,computed} from 'vue'

  let firstName = ref('zhang')
  let lastName = ref('san')

  // 计算属性——只读取,不修改
  /* let fullName = computed(()=>{
    return firstName.value + '-' + lastName.value
  }) */


  // 计算属性——既读取又修改
  let fullName = computed({
    // 读取
    get(){
      return firstName.value + '-' + lastName.value
    },
    // 修改
    set(val){
      console.log('有人修改了fullName',val)
      firstName.value = val.split('-')[0]
      lastName.value = val.split('-')[1]
    }
  })
</script>

侦听器

watch

作用:监视数据的变化。

返回值:watch()函数返回值是一个函数,调用该函数可以停止监视。

1、监视ref定义的数据类型

监视基本类型,直接写数据名,监视其value值的改变。

监视对象类型,直接写数据名,监视的是对象的地址值,若想监视对象内部的数据,要手动开启深度监视。

注意:

若修改的是ref定义的对象中的属性,newValueoldValue 都是新值,因为它们是同一个对象。

若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

2、监视reactive定义的响应式对象
<script setup>
	import { ref , watch } from 'vue'
    let sum = ref(0)
    let a = {name : "wuhu", age : 20}
    
    //监视【ref】定义的【基本类型】数据
    const stopwatch = watch( sum (newvalue,oldvalue)=>{
        console.log('sum变化了',newValue,oldValue)
    	if(newValue >= 10){
      	stopWatch()
    	}
    })
    /* 
    监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
    watch的第一个参数是:被监视的数据
    watch的第二个参数是:监视的回调
    watch的第三个参数是:配置对象(deep、immediate、once等等.....) 
  */
  watch(a,(newValue,oldValue)=>{
    console.log('a变化了',newValue,oldValue)
  },{deep:true})
    
  // 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
  watch(a,(newValue,oldValue)=>{
    console.log('a变化了',newValue,oldValue)
  })
</script>
3、监视对象中的某个属性

1、若该属性值不是对象类型,需要写成函数形式。

2、若该属性仍是对象类型,可直接编写,但推荐使用函数形式。

注意:

​ 若是对象监视的是地址值,若想监视内部的值,需要手动开启深度监视。

<script setup>
	import { reactive, watch } from 'vue'
    
    let person = reactive({
        name : "wuhu",
        age : 20,
        hobby : {
        	book : "love",
        	game : "pices"
    	}
    })
    //监视响应式对象中的基本类型的属性
    watch(()=>person.age,(newvalue,oldvalue)=>{
        console.log("person.age改变了",newvalue,oldvalue)
    })
    //监视响应式对象中的对象类型的属性
    watch(()=>person.hobby,(newvalue,oldvalue)=>{
        console.log("person改变了",newvalue,oldvalue)
    },{deep:true})
</script>
4、监视多种数据

watch函数的第一个参数传入一个数组,数组中可以包含上述类型。

watch([person,()=>person.name],(newvalue,oldvalue)=>{dosomething},{deep:true})
watchEffect

立即执行这个函数,同时响应式的追踪其依赖,并在依赖更改时重新执行该函数。

不用明确指出监视的数据,函数中用到哪些属性,就监视哪些属性。

<script>
	import {ref,watchEffect} from 'vue'
    let name = ref("wuhu")
    let age = ref(20)
    let hobby = ref({
     	book : "love",
        game : "pices"   
    })
    const stopwatch = watch(()=>{
        dosomething use those attribute
        //停止监听
        stopwatch()
    })
</script>

模板引用(元素的ref属性)

ref是一个特殊的attribute,它允许我们在一个特定的DOM元素或子组件实例被挂载后,获得对它的直接引用。

用在普通DOM标签上,获取的是DOM节点

用在普通DOM节点上
<template>
	<input ref="myinput" />
</template>

<script>
	import { useTemplateRef, onMonted } from 'vue'
    
    //第一个参数必须与模板中的ref值匹配
    const myinput = useTemplateRef('myinput')
    onMonted(()=>{
        myinput.value.focus()
    })
</script>

在含有v-for指令上的节点上,返回的是一个数组!!!

用在组件标签上

用在组件标签上,获取的是组件实例对象

//父组件
<template>
  <Child ref="child" />
</template>

<script setup>
import { useTemplateRef, onMounted } from 'vue'
import Child from './Child.vue'

const childRef = useTemplateRef('child')

onMounted(() => {
  // childRef.value 将持有 <Child /> 的实例
})
</script>

使用了<script setup>的组件是默认私有的,父组件是无法访问到一个使用<script setup>的子组件中的任何东西,除非子组件在其中通过defineExpose宏显示暴露。

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
  a,
  b
})
</script>

当父组件通过模板引用获取到了该组件的实例时,得到的实例类型为 { a: number, b: number } (ref 都会自动解包,和一般的实例一样)。

hooks(组合式函数)

setup函数中使用的Component API进行封装,提升代码的复用率。

创建hooks文件夹,在文件夹中创建useXxx.js并向外暴露。

// useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'

// 按照惯例,组合式函数名以“use”开头
export default function useMouse() {
  // 被组合式函数封装和管理的状态
  const x = ref(0)
  const y = ref(0)

  // 组合式函数可以随时更改其状态。
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  // 通过返回值暴露所管理的状态
  return { x, y }
}

在组件中使用

<template>Mouse position is at: {{ x }}, {{ y }}</template>

<script setup>
import { useMouse } from './hooks/useMouse.js'

const { x, y } = useMouse()
</script>

组件

推荐使用单文件组件。组件名建议使用PascalCase式。

注册组件

组件在模板中使用之前需要先进行注册。

全局注册

在main.js文件中,调用Vue实例对象的.component()方法,让组件在当前Vue应用中全局可用。

import {createApp} from 'vue'

const app = createApp({})

//方法一
app.component(
	//注册名字
    'MyComponent',
    //组件的实现
   {/**/}
)
//方法二:先引入再使用
import MyComponent from './MyComponent.vue'
app.component('MyComponent',MyComponent)
//方法三:使用时引入
app.component('MyComponent',()=>import('./MyComponent.vue'))

.component()方法可以被链式调用:

app
  .component('ComponentA', ComponentA)
  .component('ComponentB', ComponentB)
  .component('ComponentC', ComponentC)
局部注册

局部注册的组件需要在父组件中显式导入,并且只能在父组件中使用。

setup中,导入的组件就可以直接使用了,无需注册

<template>
  <ComponentA />
</template>

<script setup>
import ComponentA from './ComponentA.vue'
</script>
生命周期

创建阶段:setup

挂载阶段:onBeforeMountonMounted

更新阶段:onBeforeUpdateonUpdated

卸载阶段:onBeforeUnmountonUnmounted

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Props

命名规则:

传递props时建议使用camelCase式定义变量。props是只读的!

Props声明

组件需要显式的声明它所接受的props,这样才能在组件中使用。props使用steup中的defineProps()宏来声明。

<script setup name = 'son'>
    //父组件中<son :foo="data",age=1/>
    //字符串数组接收
	const props = defineProps(['foo']) 
    //对象形式接收
    defineProps({
        foo:String,
        age:Number
    })
</script>

对于对象形式声明每个属性,key是props的名称,值是该props预期类型的构造函数。

Props校验
defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // 必传但可为 null 的字符串
  propD: {
    type: [String, null],
    required: true
  },
  // Number 类型的默认值
  propE: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propF: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  }
})
组件事件

父组件通过v-on(缩写@)来监听事件:

<template>
<MYComponent @some-event="callback"/>
//当MyComponent组件中触发someEvent时,父组件会执行callback函数,函数也能接收参数
</template>

组件的事件监视器也支持事件修饰符,eg:.once

子组件

1、声明触发的事件:

使用defineEmits()宏来声明要触发的事件:

​ 函数参数有两种

  • 数组

    <script setup>
    const emit = defineEmits(['someEvent'])
    </script>
    
  • 对象

    <script setup>
    const emit = defineEmits({
      // 没有校验
      click: null,
    
      // 校验 submit 事件
      submit: ({ email, password }) => {
        if (email && password) {
          return true
        } else {
          console.warn('Invalid submit event payload!')
          return false
        }
      }
    })
    
    function submitForm(email, password) {
      emit('submit', { email, password })
    }
    </script>
    

2、返回值

defineEmits函数的返回值是一个函数,函数的第一个参数是要触发事件的名称,后面的参数是触发事件传递的值。

所有传入 emit() 的额外参数都会被直接传向监听器。举例来说,emit('foo', 1, 2, 3) 触发后,监听器函数将会收到这三个参数值。

组件v-modle

在组件上使用可以实现双向数据绑定。

父组件通过v-modle传递。

子组件通过defineModel()宏,声明传递的数据,返回值是一个ref,能够访问和修改。

<script setup>
	let modle = defineModle()//父组件未传参
    //父组件传参,可以传递多个参数
    let age = defineModle('age')
</script>
透传Attributes

透传Attributes指的是传递给一个组件的attribute,却没有被该组件声明为props或emits的attribute或者v-on事件监听器的attribute。

在模板中使用

若在子组件中是以单元素为根,则会默认继承到该根元素上。元素也可以是组件元素。

若想禁止透传可以在setup中使用defineOpinion({inheritAttrs: false})禁用。

在模板中可以通过$attrs直接访问到透传的attributes,可以在子组件中在模板的DOM元素或组件元素使用v-bind = "$attrs"来绑定要透传到哪个元素上。若有多个根节点,一定要绑定,不然会报错。

//子组件
<template>
	<header>...</header>
	<main v-bind="$attrs">...</main>//孙组件
	<footer>...</footer>
</template>
在javaScript中访问

<script setup>中使用useAttrs()API来访问一个组件的所有透传attribute

<script setup>
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>
插槽

父组件提供插槽内容,并在子组件中将这部分模板内容渲染出来。模板内容中可以使用父组件中的的data。

默认插槽

在子组件中直接使用<slot>标签,当组件标签没有传入模板内容时,将展现<slot>标签中的内容。

具名标签

在子组件中的slot标签设置name属性,父组件中可以使用<template>(该标签不会被渲染出来),并设置v-slot命令的参数指向需放置的solt标签的name属性值。

//子组件BaseLayout.vue
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

//父组件
<BaseLayout>
  <template v-slot:header>
    <!-- header 插槽的内容放这里 -->
  </template>
</BaseLayout>

默认插槽相当于设置:v-slot:default,简写为#default

条件插槽

在子模版中,可以使用$slot访问到传过来的模板要放到插槽的name值,联和条件指令可以很好的控制未传来插槽内容的插槽要不要展示。

<template>
  <div class="card">
    <div v-if="$slots.header" class="card-header">
      <slot name="header" />
    </div>
    
    <div v-if="$slots.default" class="card-content">
      <slot />
    </div>
    
    <div v-if="$slots.footer" class="card-footer">
      <slot name="footer" />
    </div>
  </div>
</template>
作用域插槽

在子组件的<slot>上传递attribute,父组件使用v-slot="xxx"来接收,并且可以在相应的含有v-slot命令的元素及其子元素上使用。

//子组件
<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</MyComponent>

//父组件
<slot name="header" message="hello"></slot>

组件拓展

pinia

实现通用的数据仓库

第一步:安装并引入pinia

npm install pinia

src/main.js引入

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

/* 引入createPinia,用于创建pinia */
import { createPinia } from 'pinia'

/* 创建pinia */
const pinia = createPinia()
const app = createApp(App)

/* 使用插件 */{}
app.use(pinia)
app.mount('#app')

**第二步:**向仓库中写数据

在src路径下创建一个大仓库store,其下又能创建多个小仓库。eg:src/store/xxx.js

它有三个概念:stategetteraction,相当于组件中的: datacomputedmethods

选项式写法:

//文件名为:count.js
//引入defineStore创建store
import {defineStore} from 'pinia'
//定义并暴露store
export const useCountStore = defineStore('count',{
    //状态
    state(){
        return {
            sum:6
        }
    },
    //getters,actions可以通过this访问到整个state
    //计算
    getters:{
        bigSum : (state)=> state.sum *2,
        moreSum : ()=>this.sum*10
    },
    //动作
    actions:{
        addSum(value){
            this.sum += 1
        }
    }
})

第三步:在组件中使用

<script setup>
    import {useCountStore} from './src/store/count.js'
    //得到对应的store
    const countStore = useCountStore()
</script>

使用数据

  • 读取数据

    store中的数据都能读取到,在setup中state中的数据要用.value访问,在模板中直接使用即可。也可使用storeToRef来进行解构state并保持响应式。

import {storeToRefs} from 'pinia'
const {sum} = storeToRefs(countStore)
  • 修改数据
//直接修改
countStore.sum=2

//批量修改
countStore.$patch({
    sum:2
})

//借助action修改
countStore.addSum(1)
  • 监视state

​ 通过store的$subscribe()方法侦听state及其变化

countState.$subscribe((mutate,state)=>{
	console.log('countState',mutate,state)
})

组合式写法

import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'

export const useTalkStore = defineStore('talk',()=>{
  // talkList就是state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )

  // getATalk函数相当于action
  async function getATalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }
  return {talkList,getATalk}
})
mitt

类似于消息订阅与发布的功能。

第一步:安装mitt

npm run mitt

第二布:新建文件(相当于容器)

src\utils\emitter.js

//引入mitt
import mitt from "mitt";
//创建emitter
const emitter = mitt()

//可以初始化事件,也可以用空容器
/*
  // 绑定事件
  emitter.on('abc',(value)=>{
    console.log('abc事件被触发',value)
  })
  emitter.on('xyz',(value)=>{
    console.log('xyz事件被触发',value)
  })

  setInterval(() => {
    // 触发事件
    emitter.emit('abc',666)
    emitter.emit('xyz',777)
  }, 1000);

  setTimeout(() => {
    // 清理事件
    emitter.all.clear()
  }, 3000); 
*/
//暴露mitt
export default emitter

第三步:绑定事件,订阅消息

<script setup>
	import emitter from "@/utils/emitter";
	import { onUnmounted } from "vue";

	// 绑定事件
	emitter.on('send-toy',(value)=>{
  	console.log('send-toy事件被触发',value)
	})

	onUnmounted(()=>{
  	// 解绑事件
  	emitter.off('send-toy')
	})
</script>

第四步:触发事件,发布消息

import emitter from "@/utils/emitter";

function sendToy(){
  // 触发事件
  emitter.emit('send-toy',toy.value)
}

路由

实现单页面应用

安装并配置:
npm install vue-router

路由组件通常存放在pagesviews文件夹,一般组件通常存放在components文件夹。

在src下创建一个router文件夹存放路由器

// src/router/index.js
import { createMemoryHistory, createRouter } from 'vue-router'

import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'

const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
]

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

在main.js中要引入router

import router from './router/index'
app.use(router)

app.mount('#app')

这步的作用包括:

  1. 全局注册RouterViewRouterLink 组件。
  2. 添加全局 $router$route 属性。
  3. 启用 useRouter()useRoute() 组合式函数。
  4. 触发路由器解析初始路由。
路由的工作模式
  1. history模式

    优点:URL更加美观,不带有#,更接近传统的网站URL

    缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。

    const router = createRouter({
    	history:createWebHistory(), //history模式
    	/******/
    })
    
  2. hash模式

    优点:兼容性更好,因为不需要服务器端处理路径。

    缺点:URL带有#不太美观,且在SEO优化方面相对较差。

    const router = createRouter({
    	history:createWebHashHistory(), //hash模式
    	/******/
    })
    
嵌套路由

路由中还可以配置子路由。在routes数组元素对象中使用children对当前路由命名。

const routes = [
    {
        path :'/home',
        component:Home
        children:[
        	{
        		path:'news',
        		component:News
    		},
    		{
                path:'games',
                component:Games
            }
        ]
    }
]

跳转路由

<router-link to="/home/news">xxx</router-link>
<!--或-->
<router-link :to="{path:'/home/news'}">xxx</router-link>
命名路由

可以简化路由跳转和传参。

在routes数组元素对象中使用name对当前路由命名。

routes:[
  {
    name:'zhuye',
    path:'/home',
    component:Home,
    children:[
        {
            name:'xinwen',
            path:'news',
            component:News
        }
    ]
  }]

在跳转路由时可以简化写法

<!--简化前:需要写完整的路径(to的字符串写法) -->
<router-link to="/home/news">跳转</router-link>

<!--简化后:直接通过名字跳转(to的对象写法配合name属性) -->
<router-link :to="{name:'xinwen'}">跳转</router-link>
路由视图

使用<router-view>来说明跳转的路由要放在哪里。

<template>
    <!-- 导航区 -->
    <div>
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <RouterLink to="/news" active-class="active">新闻</RouterLink>
      <RouterLink to="/about" active-class="active">关于</RouterLink>
    </div>
    <!-- 展示区 -->
    <div>
      <RouterView></RouterView>
    </div>
</template>

<script lang="ts" setup name="App">
  import {RouterLink,RouterView} from 'vue-router'  
</script>
命名视图

同时展示多个同级路由视图。多个视图也就意味着有多个组件,因此在路由配置中的routes数组元素对象中的component要改为使用components配置项。

<template>
	<router-view name = "news"></router-view>
	<router-view name = "games"></router-view>
	<router-view></router-view>//没有名字就默认default
</template>

配置项

const routes = [
    {
        path:'/home',
        component:Home,
        children:[
            {
                path:"all",
                components:{
                    default:News,
                    //Games:Games的缩写
                    Games,
                    //与router-view上的name属性匹配
                }
            }
        ]
    }
]
replace属性
  1. 作用:控制路由跳转时操作浏览器历史记录的模式。

  2. 浏览器的历史记录有两种写入方式:分别为pushreplace

    • push是追加历史记录(默认值)。
    • replace是替换当前记录。
  3. 开启replace模式:

    <RouterLink replace .......>News</RouterLink>
    
路由组件传参

两个重要API,useRouteruseRoute在script代码段中使用获取路由器和当前路由。在<template>中使用$router$route同样能获得。

query参数

1、传递参数

<!-- 跳转并携带query参数(to的字符串写法) -->
<router-link to="/news/detail?a=1&b=2&content=欢迎你">
	跳转
</router-link>
				
<!-- 跳转并携带query参数(to的对象写法) -->
<RouterLink 
  :to="{
    //name:'xiang', //用name也可以跳转
    path:'/news/detail',
    query:{
      id:news.id,
      title:news.title,
      content:news.content
    }
  }"
>
  {{news.title}}
</RouterLink>

2、接收参数

//Detail.vue
<script setup>
	import {useRoute} from 'vue-router'
	const route = useRoute()
	// 打印query参数
	console.log(route.query)
</script>
params参数

1、规则占位

const routes=[
    {
        path:'news',
        component:News,
        children:[
            {
                name:'xiang',
                path:'detail/:id/:title/:content',
                component:Detail
            }
        ]
    }
]

2、传递参数

<!-- 跳转并携带params参数(to的字符串写法) -->
<RouterLink :to="`/news/detail/001/新闻001/内容001`">{{news.title}}</RouterLink>
				
<!-- 跳转并携带params参数(to的对象写法) -->
<RouterLink 
  :to="{
    name:'xiang', //必须用name跳转
    params:{
      id:news.id,
      title:news.title,
      content:news.title
    }
  }"
>
  {{news.title}}
</RouterLink>

3、接收参数

//News.vue
import {useRoute} from 'vue-router'
const route = useRoute()
// 打印params参数
console.log(route.params)

备注1:传递params参数时,若使用to的对象写法,必须使用name配置项,不能用path

备注2:传递params参数时,需要提前在规则中占位。

路由的props配置

让路由组件更方便的收到参数(可以将路由参数作为props传给路由组件)

//方法一
// props的布尔值写法,作用:把收到了每一组params参数,作为props传给Detail组件
{
	name:'xiang',
	path:'detail/:id/:title/:content',
	component:Detail,
  	props:true
    //底层在调用此规则时相当于<Detail id=" " title=" " content=" ">
}

//方法二
// props的函数写法,作用:把返回的对象中每一组key-value作为props传给Detail组件
{
	name:'xiang',
	path:'detail/:id/:title/:content',
	component:Detail,
  	props(route){
    return route.query
  }
}

//方法三
// props的对象写法,作用:把对象中的每一组key-value作为props传给Detail组件
{
	name:'xiang',
	path:'detail/:id/:title/:content',
	component:Detail,
  	props:{a:1,b:2,c:3}//此时的props是静态不变的
}

在路由组件中使用

<script setup>
	defineProps(['id','title','content'])
</script>
编程式路由导航

除了借助<router-link>创建a标签来定义导航链接,还可以借助router实例的方法,编写代码来实现跳转。

router.push

该方法会向 history 栈添加一个新的记录,当用户点击浏览器后退按钮时,会回到之前的 URL。

<script setup>
	import {useRouter} from 'vue-router'
    // 字符串路径
	router.push('/users/eduardo')

	// 带有路径的对象
	router.push({ path: '/users/eduardo' })

	// 命名的路由,并加上参数,让路由建立 url
	router.push({ name: 'user', params: { username: 'eduardo' } })

	// 带查询参数,结果是 /register?plan=private
	router.push({ path: '/register', query: { plan: 'private' } })

	// 带 hash,结果是 /about#team
	router.push({ path: '/about', hash: '#team' })
</script>

注意:当使用对象写法时,若使用path属性,则params会被忽略。

router.replace

该方法与router.push( )用法近乎一致,只不过不会向history栈添加一个记录,而是取代原有的记录。

router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })

router.go

该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步。

// 向前移动一条记录,与 router.forward() 相同
router.go(1)

// 返回一条记录,与 router.back() 相同
router.go(-1)
重定向和别名
重定向

将特定的路径,重新定向到已有路由。重定向是通过router配置来完成的。

重定向完URL会被改变的。例如:访问 /home 时,URL 会被 / 替换,然后匹配成 /

//从 /home 重定向到 /:
const routes=[{path:'/home',redirect:'/'}]

//重定向的目标也可以是一个命名的路由
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]

//也可以是一个方法,动态返回重定向目标
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: '/search/:searchText',
    redirect: to => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { path: '/search', query: { q: to.params.searchText } }
    },
  },
  {
    path: '/search',
    // ...
  },
]

也可以重定向到相对位置

const routes = [
  {
    // 将总是把/users/123/posts重定向到/users/123/profile。
    path: '/users/:id/posts',
    redirect: to => {
      // 该函数接收目标路由作为参数
      // 相对位置不以`/`开头
      // 或 { path: 'profile'}
      return 'profile'
    },
  },
]
别名

/ 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /

const routes = [{ path: '/', component: Homepage, alias: '/home' }]

有参数的在别名中同样要设置。

const routes = [
  {
    path: '/users/:id',
    component: UsersByIdLayout,
    children: [
      // 为这 3 个 URL 呈现 UserDetails
      // - /users/24
      // - /users/24/profile
      // - /24
      { path: 'profile', component: UserDetails, alias: ['/:id', ''] },
    ],
  },
]

内置组件

Transition

<Transition>可以将进入和离开动画通过默认插槽传递给他的元素或组件上。v-ifv-show均可触发。

<button @click="show = !show">Toggle</button>
<Transition>
  <p v-if="show">hello</p>
</Transition>
/* 下面我们会解释这些 class 是做什么的 */
.v-enter-active,
.v-leave-active {
  transition: opacity 0.5s ease;
}

.v-enter-from,
.v-leave-to {
  opacity: 0;
}

也可以为过渡效果命名

<Transition>组件传入nameprops来声明一个过度效果名。

<Transition name="fade">
  ...
</Transition>
//注意!!!改名
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
TransitionGroup

<TransitionGroup> 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。

<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</TransitionGroup>
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
  position: absolute;
}
  • 默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
  • 列表中的每个元素都必须有一个独一无二的 key attribute。
  • CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
Teleport

<Teleport> 可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

<teleport to='body' >
    <div class="modal" v-show="isShow">
      <h2>我是一个弹窗</h2>
      <p>我是弹窗中的一些内容</p>
      <button @click="isShow = false">关闭弹窗</button>
    </div>
</teleport>
Suspense
  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验
  • 使用步骤:
    • 异步引入组件
    • 使用Suspense包裹组件,并配置好defaultfallback
import { defineAsyncComponent,Suspense } from "vue";
const Child = defineAsyncComponent(()=>import('./Child.vue'))
<template>
    <div class="app">
        <h3>我是App组件</h3>
        <Suspense>
          <template v-slot:default>
            <Child/>
          </template>
          <template v-slot:fallback>
            <h3>加载中.......</h3>
          </template>
        </Suspense>
    </div>
</template>

API

全局API

应用实例API
createApp

创建一个应用实例

类型:function createApp(rootComponent[,rootProps])

第一个参数是根组件。第二个是要传给根组件的props。

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

const app = createApp(App)
app.mount()

将应用实例挂载在一个容器元素中。

app.mount(rootContainer)

参数可以是一个实际的DOM元素,也可以是CSS选择器(使用第一个匹配到的元素)。返回根组件的实例。

import { createApp } from 'vue'
const app = createApp(/* ... */)

app.mount('#app')
//app.mount(document.body.firstChild)
app.component()

如果同时传递一个字符串及其定义,则注册一个全局组件。

如果只传递一个名字,则会返回用该名字注册的组件(如果存在的话)。

import { createApp } from 'vue'

const app = createApp({})

// 注册一个选项对象
app.component('my-component', {
  /* ... */
})

// 得到一个已注册的组件
const MyComponent = app.component('my-component')
app.use()

安装一个插件

import { createApp } from 'vue'
import MyPlugin from './plugins/MyPlugin'

const app = createApp({
  /* ... */
})

app.use(MyPlugin)
app.provide()

全局提供一个值,可在应用实例的所有后代中注入(inject)使用。

第一个参数是注入的key,第二个参数是提供的值。

import { createApp } from 'vue'

const app = createApp(/* ... */)

app.provide('message', 'hello')
app.directive()

若传入两个参数则是全局注册自定义指令。若传入一个参数则返回用该名称定义的指令。

import { createApp } from 'vue'

const app = createApp({
  /* ... */
})

// 注册(对象形式的指令)
app.directive('my-directive', {
  /* 自定义指令钩子 */
})

// 注册(函数形式的指令)
app.directive('my-directive', () => {
  /* ... */
})

// 得到一个已注册的指令
const myDirective = app.directive('my-directive')
app.config

每个应用实例都会暴露一个config对象,其中包含了对这个应用的配置设定。可以在挂载前更改这些属性。

import { createApp } from 'vue'

const app = createApp(/* ... */)

console.log(app.config)
app.config.globalProperties

用于注册能够被应用内所有组件实例访问到的全局属性的对象。

用法:app.config.globalProperties.attributeName = value/function

之后在任意组件都可用。

通用
version

暴露当前所使用的Vue版本

import { version } from 'vue'

console.log(version)
nextTick()

等待下一次DOM更新刷新的工具方法。

<template>
  <button id="counter" @click="increment">{{ count }}</button>
</template>

<script setup>
import { ref, nextTick } from 'vue'

const count = ref(0)

async function increment() {
  count.value++

  // DOM 还未更新
  console.log(document.getElementById('counter').textContent) // 0

  await nextTick()
  // DOM 此时已经更新
  console.log(document.getElementById('counter').textContent) // 1
}
</script>

UI组件库

移动端常用 UI 组件库
  1. Vant https://youzan.github.io/vant
  2. Cube UI https://didi.github.io/cube-ui
  3. Mint UI http://mint-ui.github.io
PC 端常用 UI 组件库
  1. Element UI https://element.eleme.cn
  2. IView UI https://www.iviewui.co
使用组件库

以Element UI为例

1、安装

npm install element-ui

2、在main.js入口文件使用element-ui插件

import {createApp} from 'vue'
// 引入element-ui
import ElementUI from 'element-ui'
// element-ui的css样式要单独引入
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'

const app = createApp()
 // 这种方式引入了ElementUI中所有的组件
app.use(ElementUI)
app.mount('#app')

3、就可以使用element-ui中的组件了。

若有不足之处请指出。谢谢!

标签:vue,const,app,入门教程,vue3,组件,import,路由
From: https://blog.csdn.net/wawu_moment/article/details/143213220

相关文章

  • 安装node及vue项目的启动
    1、ubuntu安装npmsudoaptinstallnodejsnpm2、设置包下载源npmconfigsetregistryhttps://registry.npmmirror.com/3.安装包及运行npminstall安装成功后会生成一个node_moudels目录运行:npmrunserve4、常见报错及解决方式(1)oldlockfile报错npmWARNoldlo......
  • vue3 学习笔记(不断更新中...)
    组合式APIsetup()11响应式APIrefref用于创建响应式数据(通常用来定义基本类型数据)在JavaScript代码中,需要使用.value来操作数据letcount=ref(1)console.log(count.value)//1count.value++console.log(count.value)//2在Template模板中不需要<scriptse......
  • (系列九)使用Vue3+Element Plus创建前端框架(附源码)
    说明  该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。   该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。   说明:OverallAuth2.0是一个简单、易懂、功能强大的权限+可视化流程管理系统。友情提醒:本篇文章是属于系......
  • Vue Router进阶学习
    各位程序员1024节日快乐~VueRouter是Vue.js的官方路由管理器,它和Vue.js的核心深度集成,让构建单页面应用(SPA)变得简单。以下是VueRouter的基本用法VueRouter基本用法安装VueRouter首先,你需要安装VueRouter。如果你使用的是npm,可以使用以下命令:npminstal......
  • vue - 菜单栏联动选项卡
    在vue环境下,制作一个与菜单联动的选项卡(el-tabs)。能看到这个文章,大体是有自己动手的打算了,这里给一下关键思路。关键点路由的设计传统的选项卡设计,一般通过iframe实现,在vue环境中,则是使用router-view。问题是,一个界面上,同时存在多个router-view(如果不做标记),内容是完......
  • chrome 控制台console 调用vue页面的方法--来自chatgpt的回答
    问题二:vue2的项目中chrome控制台输入$0.vue会输出什么在Vue2项目中,如果你在Chrome控制台中输入$0.__vue__,这个命令会返回$0当前选中的DOM元素对应的Vue实例。解释:$0:代表ChromeDevTools中当前选中的DOM元素。.vue:这是Vue2中的一个内部属性,它持有与该D......
  • vue - 选项卡右击下拉框
    在element-ui环境下,给选项卡添加右击事件,是相当麻烦的一件事情,主要是麻烦,很多东西都需要注意,并没有太多难点。注意项el-tabs的右击事件事件的名称是contextmenu.prevent.native,这个很快就能找到,需要注意的是:选项卡整个头部都能触发右击事件,需要过滤出哪些事件是由选项卡......
  • vue - 自定义吸附窗口
    业务需求以共享单车界面为例,地图上分布着大量的共享单车,鼠标悬浮在单车上,弹出一个吸附弹窗,内容显示单车详细信息。分析很明显,因为单车的数量可能非常多,我们不可能用显示隐藏的方式实现;合理的做法是,所有单车公用一个弹窗面板,悬浮的时候刷新面板上的数据。方案看着改吧,element......
  • 基于SpringBoot和Vue的地方美食分享与推荐网站的设计与实现(源码+定制+开发)地方美食推
    博主介绍:  ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生......
  • 基于springboot+vue的Hadoop的高校教学资源平台的设计与实现(源码+lw+部署文档+讲解等
    课题摘要基于SpringBoot+Vue的Hadoop高校教学资源平台是一个功能强大的教学资源管理系统,结合了先进的技术架构和丰富的功能模块,为高校教学提供了高效、便捷的资源共享和管理平台。以下是该平台的设计与实现方案,包括源码、LW(LiveWire)、部署文档和讲解等内容。一、......