vue-知识点

65 阅读9分钟

API

1、createApp

  1. 创建vue实例
import { createApp } from 'vue'

const app = createApp({
  /* 根组件选项 */
})
//可以传入根组件选项和app
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

2、createSSRApp

  1. 以SSR激活模式创建vue实例
  2. 用法与createAPP相同

3、app.mount

参数可以是一个实际的 DOM 元素或一个 CSS 选择器 (使用第一个匹配到的元素)。返回根组件的实例。 如果该组件有模板或定义了渲染函数,它将替换容器内所有现存的 DOM 节点。否则在运行时编译器可用的情况下,容器元素的 innerHTML 将被用作模板。 在 SSR 激活模式下,它将激活容器内现有的 DOM 节点。如果出现了激活不匹配,那么现有的 DOM 节点将会被修改以匹配客户端的实际渲染结果。 对于每个应用实例,mount() 仅能调用一次。

4、app.component()

1.注册全局组件方法一: app.component('Comp',Comp)传入组件名和组件实例,Comp是SFC

<script setup>
import { ref,createApp } from 'vue'
import Comp from './Comp.vue'

const msg = ref('Hello World!')
const app = createApp({})
app.component('Comp',Comp)
</script>

<template>
  <h1>{{ msg }}</h1>
  <Comp/>
  <input v-model="msg" />
</template>
  1. 注册全局组件方法二 传入配置项{template:'',data:function (){return {}}}
Vue.component("my-component",
{ template:"<div @click='count++'>{{count}}</div>", 
data: function(){ return {count:0} } 
})

1、声明式渲染

1.1、单文件组件

  1. Vue 单文件组件 (Single-File Component,缩写为 SFC)。
  2. 将从属于同一个组件的 HTML、CSS 和 JavaScript 封装在使用 .vue 后缀的文件中。

1.2、响应式对象

  1.  reactive() API 来声明响应式状态。
  2.  将初始对象作为参数传入
  3. 由 reactive() 创建的对象都是 JavaScript Proxy,其行为与普通对象一样:
import { reactive } from 'vue'

const counter = reactive({
  count: 0
})

console.log(counter.count) // 0
counter.count++
  1. ref可以包装任何类型的值,参数是初始值
  2. 返回一个对象,有value属性
import { ref } from 'vue'
const message = ref('Hello World!')
console.log(message.value) // "Hello World!"
message.value = 'Changed'

把数据包装成响应式数据之后,修改数据,页面会同步展示

<script setup>
import { ref } from 'vue'
let message = ref('make me dynamic')
message = '556'
// 组件逻辑
// 此处声明一些响应式状态
</script>

<template>
  <h1>{{message}}</h1>
</template>

2、属性绑定

语法::属性名 = “对象名”

<div :id="dynamicId"></div>

2.1 class绑定语法

不要忘记:和“”

  1. 值为对象:键名为类名,键值为是否显示类名
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
  1. 数组语法-每一个数组名就是一个类 <div v-bind:class="[activeClass, errorClass]"></div>

3、事件监听

语法-@click = “事件处理函数名”注意别加括号

4、表单绑定

将input的value值和text值绑定,不用手写oninput函数。

<input v-model="text">

5、if else

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

6、列表渲染

<ul>
  <li v-for="todo in todos" :key="todo.id">
    {{ todo.text }}
  </li>
</ul>
  1. v-for="todo in todos"

应用实例-添加列表项-删除列表项

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

// 给每个 todo 对象一个唯一的 id
let id = 0

const newTodo = ref('')
const todos = ref([
  { id: id++, text: 'Learn HTML' },
  { id: id++, text: 'Learn JavaScript' },
  { id: id++, text: 'Learn Vue' }
])

function addTodo() {
  todos.value.push({ id: id++, text: newTodo.value })
  newTodo.value = ''
}

function removeTodo(todo) {
  todos.value = todos.value.filter((t) => t !== todo)
}
</script>

<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
</template>
  1. 上面是一个单文件组件例子
  2. 在script里面定义变量和函数,在template里面定义视图模版
  3. <input id = 'todo.id' type = "checkbox" v-model="todo.done" name = "course">{{todo.text}}

computed计算属性

  1. 些数据是根据现有的响应式数据计算得出时,就可以使用计算属性(computed properties)。
  2. 计算属性会基于它们依赖的响应式数据进行计算,并且会缓存计算结果
  3. 只有在响应式数据变化时才会重新计算。
  4. 参数是箭头函数,返回新的值
const completedTodos = computed(() => { return todos.value.filter(todo => todo.done) })

watch侦听器

watch(todoId,()=>{
  todoData.value.id = todoId
})
  1. 有两个参数,第一个参数是被侦听的响应式数据
  2. 第二个参数是回调函数,处理副作用
  3. 一旦被侦听的数据改变,就会执行回调函数

props

  1. 父组件给子组件传递动态参数,要用:v-bind语法
  <ChildComp :msg = "greeting" />
  //如果不用:语法会显示greeting
  1. 子组件引入props
  2. vue3提出的defineprops可以在编译时优化
const props = defineProps({ title: String, count: { type: Number, default: 0 } })

@input="$emit('update:modelValue', $event.target.value)"解析

  • @input:这是 Vue 中用于监听输入事件的一种缩写语法。它等价于 v-on:input,表示监听 <input> 元素的输入事件。
  • $emit('update:modelValue', $event.target.value):这是在输入事件触发时执行的表达式。
  • $emit 是 Vue 实例的方法,用于触发自定义事件。在这里
  • 它触发了一个名为 update:modelValue 的自定义事件,并传递了一个参数 $event.target.value
  • 其中 $event 是事件对象,$event.target.value 表示输入框当前的值。

总的来说,这段代码的作用是:当 <input> 元素的值发生变化时,触发一个名为 update:modelValue 的自定义事件,并将输入框的当前值作为参数传递给父组件。这种模式通常用于实现 Vue 中的双向绑定。

插槽

除了通过 props 传递数据外,父组件还可以通过插槽 (slots) 将模板片段传递给子组件:

<ChildComp>
  This is some slot content!
</ChildComp>

传入的值会在子组件的slot处展示

<template>
<slot></slot>
</template>

1、$emit

<!-- ChildComponent.vue -->
<template>
  <button @click="emitEvent">Click me!</button>
</template>

<script>
export default {
  methods: {
    emitEvent() {
      // 触发名为 'custom-event' 的自定义事件,并传递一些数据
      this.$emit('custom-event', 'Hello from ChildComponent!');
    }
  }
}
</script>
  1. 父组件定义函数methods: { handleCustomEvent(data) { // 当 'custom-event' 事件被触发时,执行这个方法 this.message = data; }
  2. 父组件传递函数给子组件<ChildComponent @custom-event="handleCustomEvent" />
  3. 子组件使用this.$emit调用父组件的函数this.$emit('custom-event', 'Hello from ChildComponent!');
<!-- ParentComponent.vue -->
<template>
  <div>
    <p>{{ message }}</p>
    <!-- 使用 ChildComponent 组件,并监听 'custom-event' 事件 -->
    <ChildComponent @custom-event="handleCustomEvent" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      message: ''
    };
  },
  methods: {
    handleCustomEvent(data) {
      // 当 'custom-event' 事件被触发时,执行这个方法
      this.message = data;
    }
  }
}
</script>

2、使用$ref

<!-- ParentComponent.vue -->
<template>
  <div>
    <button @click="incrementChildCounter">Increment Child Counter</button>
    <!-- 使用 ref 特性引用 ChildComponent -->
    <ChildComponent ref="childComponentRef" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    incrementChildCounter() {
      // 通过 this.$refs 访问引用的子组件,并调用子组件的方法
      this.$refs.childComponentRef.increment();
    }
  }
}
</script>
  1. 子组件添加ref属性 <ChildComponent ref="childComponentRef" />
  2. 父组件获取子组件对象:this.$refs.childComponentRef.increment();

3、使用provide/injectprovide/inject

<!-- ParentComponent.vue -->
<template>
  <div>
    <!-- 使用 ChildComponent 组件 -->
    <ChildComponent />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  provide() {
    // 提供一个名为 message 的数据
    return {
      message: 'Hello from ParentComponent!'
    };
  }
}
</script>
<!-- ChildComponent.vue -->
<template>
  <div>
    <p>{{ providedMessage }}</p>
  </div>
</template>

<script>
export default {
  inject: ['message'], // 注入名为 message 的数据

  computed: {
    providedMessage() {
      // 使用注入的 message 数据
      return this.message;
    }
  }
}
</script>

  1. 父组件provide() { // 提供一个名为 message 的数据 return { message: 'Hello from ParentComponent!' }; }returnreturn一个对象有messagemessage属性

  2. 子组件 inject: ['message'], // 注入名为 message 的数据 然后使用this.message

3、事件总线

首先,我们需要创建一个事件总线实例。我们可以在单独的文件中创建它,例如 EventBus.js

// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();

然后在 SiblingA 组件中,当按钮被点击时,我们触发一个自定义事件,并通过事件总线发送消息

  1. EventBus.$emit('message', 'Hello from SiblingA!');
<!-- SiblingA.vue -->
<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
import { EventBus } from './EventBus';

export default {
  methods: {
    sendMessage() {
      // 触发名为 'message' 的自定义事件,并传递消息
      EventBus.$emit('message', 'Hello from SiblingA!');
    }
  }
}
</script>

接下来,在 SiblingB 组件中,我们监听 message 事件,并在事件触发时接收并显示收到的消息: EventBus.$on('message', message => {});

<!-- SiblingB.vue -->
<template>
  <div>
    <p>Received Message: {{ receivedMessage }}</p>
  </div>
</template>

<script>
import { EventBus } from './EventBus';

export default {
  data() {
    return {
      receivedMessage: ''
    };
  },
  mounted() {
    // 监听名为 'message' 的自定义事件
    EventBus.$on('message', message => {
      // 收到消息后更新 receivedMessage 数据
      this.receivedMessage = message;
    });
  }
}
</script>

1、setup

  1. <script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 <script> 语法,它具有更多优势:
  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 TypeScript 声明 props 和自定义事件。
  • 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
  • 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
  • 更好的类型推断:由于 setup() 函数中的代码是在编译时执行的,而不是在运行时执行的,因此 TypeScript 能够更好地推断出组件的类型信息,从而提供更好的类型检查和错误提示。
  • 更好的性能优化setup() 函数中的代码执行时机是在组件实例创建之前
  • 与普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行

1.1 、顶层的绑定会被暴露给模板

<script setup>
// 变量
const msg = 'Hello!'
import { capitalize } from './helpers'

// 函数
function log() {
  console.log(msg)
}
</script>

<template>
  <button @click="log">{{ msg }}</button>
  <div>{{ capitalize('hello') }}</div>
</template>
  1. 可以在模板表达式中直接使用导入的 helper 函数,而不需要通过 methods 选项来暴露它。

2、动态组件

  1. <component :is="currentComponent"></component>
  2. 根据:is 的值判断显示哪个组件
<template>
  <div>
    <button @click="currentComponent = 'Home'">Home</button>
    <button @click="currentComponent = 'About'">About</button>
    <component :is="currentComponent"></component>
  </div>
</template>

<script>
import Home from './components/Home.vue';
import About from './components/About.vue';

export default {
  components: {
    Home,
    About
  },
  data() {
    return {
      currentComponent: 'Home'
    };
  }
};
</script>

3、命名空间组件

<script setup>
import * as Form from './form-components'
</script>

<template>
  <Form.Input>
    <Form.Label>label</Form.Label>
  </Form.Input>
</template>

举例

src/
|-- components/
|   |-- Form/
|   |   |-- Input.vue
|   |   |-- Select.vue
|   |-- UI/
|       |-- Button.vue
|       |-- Modal.vue

<template>
  <div>
    <Form.Input />
    <UI.Button />
  </div>
</template>

<script setup>
import Form from '@/components/Form/Input.vue';
import UI from '@/components/UI/Button.vue';
</script>

4、自定义指令

<template>
  <div>
    <input v-my-upper-directive />
    <p v-my-upper-directive>This text will be converted to uppercase</p>
  </div>
</template>

<script setup>
const vMyUpperDirective= {
  mounted(el) {
    el.addEventListener('input', () => {
      el.value = el.value.toUpperCase();
    });
  }
};
</script>
  1. 在 Vue 自定义指令中,el 是指令绑定的目标元素,即指令所作用的 DOM 元素。在 mounted 钩子函数中,el 参数表示指令所绑定的 DOM 元素。
  2. 上面代码中el 表示使用自定义指令的元素,例如 <input v-uppercase /><p v-uppercase> 中的 <input><p> 元素。在这个例子中,el 将分别指向这两个元素。

获取dom

哪一个生命周期都可以,只要在异步方法中

beforeCreate

拿不到method中的方法

在created中还是mounted中请求

根据情况,如果希望子组件的先展示则在mounted中请求

keep-alive

  1. 新增生命周期activited deactivited
  2. 缓存组件
  3. <keep-alive>组件</keep-alive>
  4. 首次进入组件执行5个生命周期
  5. 后续进入组件执行1个activited

生命周期使用情况

image.png

this.$parent

可以直接修改父组件的数据

provide/inject

  1. 只能向下传递 provide(){retturn { value: 'value'}} inject: ['value']

子组件传值给父组件

  1. this.$children
  2. this.$emit('','')

ref/refs

this.refs.child ref = 'child

eventBus

import bus from './util/bus.js'
bus.$emit('change',this.str)
子组件
bus.$on('change',(str)=>{})

this.$root

返回根组件

slot

父组件
<List>
<template #header>
<div>hello</div>
</template>
</List>
子组件
<slot name = 'header'>

作用域插槽

子组件
<slot :air = 'air'></slot>
父组件
<template #header = '{air}'></template>

vuex

用法

//vuex文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use('Vuex')
export default new Vuex.Store({
state:{ str : '123'},
getters:{},
mutations:{},
actions:{},
modules:{}
})
//其他组件
this.$store.state.str

mapState

import mapState from 'vuex'
computed :{...mapState(['str'])}
mapState是一个函数,接受的参数可以是对象也可以是数组,将Stroe仓库的数据复制了一份。

getters

vuex文件
getters:{
changeStr(state){
return state.str = '123'
}
使用组件
$store.getters.changeStr
or
import mapGetters from 'vuex'
computed:{
...mapGetters(['changeStr'])
}
}
两种都无法改变原来的数据,只能获取

mutation和action

1.mutation只能执行同步操作
2. action是提交mutation的,可以写异步操作
3. 只能通过mutation修改state
mutation:{
changeNumber(state){
state.count++
}
}
this.$store.commit('changeNumber')

action:{
changeNumberAsync({commit}){
setTimeOut(()=>{
commit('changeNumber')
},1000)
}
}
this.$store.dispatch('changeNumberAsync')

vuex实现持久化存储

  1. 自己写localStorage
  2. 使用插件vuex-persistedstate
import 'createPersistedState' from 'vuex-persistedstate'
Vue.use('vuex')
const store = new Vuex.store({
plugin:[
createPersistedState({
storage:window.sessionStorage,
key:'store'
})
]
})

路由

安装

  1. 下载cdn
  2. 使用包管理器 npm install vue-router@4
  3. 使用create-vue脚手架自动加入vue-router选项
  4. import {createRouter} from 'vue-router'

router-link

router-view

app.use(router)

app.use(router)//使整个应用支持router
//router对象是路由对象,由createRouter创建
const router = VueRouter.createRouter({
history:VueRouter.createWebhasHistory(),
routes,
})
//routes是路由配置,是路径和组件的对应关系
//是对象数组,对象有path和component属性
const routes = [{path:'/', component:Home},{path:'/about', component:About}]

常见模式

  1. hash #
  2. history /

找不到页面

  1. history会给后端发送请求
  2. hash模式不会

打包的差异

  1. 配置publicPath:''./,然后运行npm run build
const router = new VueRouter({
mode:'history/hash' //如果选择history模式,自测时看不到内容,hash模式可以看到
})

当前页跳转当前页故障

  1. 在routerPush里面加上catch(error => error)

routerrouter和route

  1. router是整个路由对象
  2. route是当前路由对象

导航守卫

  1. 全局前置守卫
router.beforeEach((from,to,next)=>{
next()
})
  1. 全局后置守卫 没有next函数,无法改变路由
router.afterEach((from,to)=>{

})
  1. 路由独享守卫 在进入一个页面之前判断是否登陆,如果没有登陆则跳转登陆页面
const router = new VueRouter({
routes:[
{
path:'',
beforeEnter:(from,to,next)=>{}
}
]
})
  1. 组件内的守卫

$set

this.$set(obj,'key',newValue)

$nextTick()

在create函数里面异步获取dom
原理是promise
this.nextTick(()=>{

})
原理
nextTick(callback){
return Promise.resolve.then(()=>callback())
}

获取根组件,数据,子节点,父节点

$el,$data, $children $parent $root

data定义数据在return内部和外部的区别

  1. 定义在return之外的数据无法定义为响应式,也就是没有get和set拦截

computded计算属性

1. 能不能直接修改

computed:{
changeStr(){
get(){
return this.str.slice(-2)
}
set(val){
this.str = val
}
}
}

可以用作v-model吗

可以,但是一定要使用get和set写法

watch用法

watch:{
str(newValue,oldValue){
execute when str changed
}
}

1. how to run watch when initiate program

immedate:true

watch: {
str:{
handle(oldvalue,newvalue){
}
immediate:true
}
}

deep watch

deep:true

the difference between method and computed attribute

  1. computed attribute has cache. only run once for the same value

directive

whole directive

  1. use Vue.directive('name',()=>{actiion :function()})
//main.js
Vue.directive('demo',()=>{
inserted:function(){

}
})