# vue 技术

Vue3 基础知识点

# 生命周期

Vue2.x Vue3
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
activated onActivated
deactivated onDeactivated
errorCaptured onErrorCaptured

Tips: setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地去定义。

# watchEffect 的使用


import {
  ref,
  watchEffect,
} from 'vue'

let sum = ref(0)

watchEffect(()=>{
  const x1 = sum.value
  console.log('watchEffect所指定的回调执行了')
})

# watch 的使用


import {
      reactive,
      watch,
    } from 'vue'
     //数据
     let sum = ref(0)
     let msg = ref('你好啊')
     let person = reactive({
                    name:'张三',
                    age:18,
                    job:{
                      j1:{
                        salary:20
                      }
                    }
                  })
    // 两种监听格式
    watch([sum,msg],(newValue,oldValue)=>{
            console.log('sum或msg变了',newValue,oldValue)
          },{immediate:true})

     watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person的job变化了',newValue,oldValue)
     },{deep:true}) 

# computed 计算属性的使用


import {
      reactive,
      computed,
    } from 'vue'

    //数据
    let person = reactive({
       firstName:'小',
       lastName:'叮当'
     })
    // 计算属性简写
    person.fullName = computed(()=>{
        return person.firstName + '-' + person.lastName
      }) 
    // 完整写法
    person.fullName = computed({
      get(){
        return person.firstName + '-' + person.lastName
      },
      set(value){
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      }
    })

# props 父子传值的使用

父组件代码如下(示例)

<template>
  <child :name='name'/>
</template>

<script setup>
    import {ref} from 'vue'
    // 引入子组件
    import child from './child.vue'
    let name= ref('小叮当')
</script>
1
2
3
4
5
6
7
8
9
10

子组件代码如下(示例)

<template>
  <span>{{props.name}}</span>
</template>

<script setup>
  import { defineProps } from 'vue'
  // 声明props
  const props = defineProps({
    name: {
      type: String,
      default: '11'
    }
  })
  // 或者
  //const props = defineProps(['name'])
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# emit 子父传值的使用

父组件代码如下(示例)

<template>
  <AdoutExe @aboutExeVisible="aboutExeHandleCancel" />
</template>
<script setup>
import {reactive} from 'vue'
// 导入子组件
import AdoutExe from '../components/AdoutExeCom'

const data = reactive({
  aboutExeVisible: false,
})
// content组件ref


// 关于系统隐藏
const aboutExeHandleCancel = () => {
  data.aboutExeVisible = false
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

子组件代码如下(示例)

<template>
   <a-button @click="isOk">
     确定
   </a-button>
</template>
<script setup>
import { defineEmits } from 'vue';

// emit
const emit = defineEmits(['aboutExeVisible'])
/**
 * 方法
 */
// 点击确定按钮
const isOk = () => {
  emit('aboutExeVisible');
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 获取子组件 ref 变量和 defineExpose 暴露

父组件代码如下(示例)

<template>
    <button @click="onClickSetUp">点击</button>
    <Content ref="content" />
</template>

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

// content组件ref
const content = ref('content')
// 点击设置
const onClickSetUp = ({ key }) => {
   content.value.modelVisible = true
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

子组件代码如下(示例)

<template>
    <p>{{data }}</p>
</template>

<script setup>
import {
  reactive,
  toRefs
} from 'vue'

/**
 * 数据部分
 * */
const data = reactive({
  modelVisible: false
})
defineExpose({
  ...toRefs(data),
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 路由 useRoute 和 useRouter 的使用

<script setup>
  import { useRoute, useRouter } from 'vue-router'

  // 声明
  const route = useRoute()
  const router = useRouter()

  // 获取query
  console.log(route.query)
  // 获取params
  console.log(route.params)

  // 路由跳转
  router.push({
      path: `/index`
  })
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# store 仓库的使用

import { useStore } from 'vuex'
import { num } from '../store/index'

const store = useStore(num)

// 获取Vuex的state
console.log(store.state.number)
// 获取Vuex的getters
console.log(store.state.getNumber)

// 提交mutations
store.commit('fnName')

// 分发actions的方法
store.dispatch('fnName')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# provide 和 inject 祖孙传值

父组件代码如下(示例)

<template>
  <AdoutExe />
</template>

<script setup>
  import { ref,provide } from 'vue'
  import AdoutExe from '@/components/AdoutExeCom'

  let name = ref('Jerry')
  // 使用provide
  provide('provideState', {
    name,
    changeName: () => {
      name.value = '小叮当'
    }
  })
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

子组件代码如下(示例)

import { inject } from 'vue'
const provideState = inject('provideState')

provideState.changeName()
1
2
3
4

# 自定义 v-model

要使自定义的 Vue 组件支持 v-model,需要实现一个名为 value 的 prop 和一个名为 input 的事件。在组件内 部,将 value prop 绑定到组件的内部状态,然后在对内部状态进行修改时触发 input 事件。

下面是一个简单的例子,展示如何创建一个自定义的输入框组件并支持 v-model

<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  name: 'MyInput',
  props: {
    value: String
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12

在上面的组件中,我们定义了一个 value prop,这是与 v-model 绑定的数据。我们还将内置的 input 事件转发 为一个自定义的 input 事件,并在事件处理程序中更新内部状态。

现在,我们可以在父组件中使用 v-model 来绑定这个自定义组件的值,就像使用普通的输入框一样

<template>
  <div>
    <my-input v-model="message" />
    <p>{{ message }}</p>
  </div>
</template>

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

export default {
  components: {
    MyInput
  },
  data() {
    return {
      message: ''
    };
  }
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

在上面的代码中,我们通过使用 v-model 指令来双向绑定 message 数据和 MyInput 组件的值。当用户在输入框 中输入文本时,MyInput 组件会触发 input 事件,并将其更新的值发送给父组件,从而实现了双向绑定的效果。

# 事件总线(EventBus)

Vue 事件总线是一个事件处理机制,它可以让组件之间进行通信,以便在应用程序中共享信息。在 Vue.js 应用程 序中,事件总线通常是一个全局实例,可以用来发送和接收事件。

以下是使用 Vue 事件总线的步骤:

3.1 创建一个全局 Vue 实例作为事件总线

import Vue from 'vue'
export const eventBus = new Vue()
1
2

3.2 在需要发送事件的组件中,使用$emit 方法触发事件并传递数据

eventBus.$emit('eventName', data)
1

在需要接收事件的组件中,使用$on 方法监听事件并处理数据

eventBus.$on('eventName', data => {
  // 处理数据
})
1
2
3

需要注意的是,事件总线是全局的,所以在不同的组件中,需要保证事件名称的唯一性。另外,需要在组件销毁前 使用$off 方法取消事件监听

eventBus.$off('eventName')
1

这样就可以在 Vue.js 应用程序中使用事件总线来实现组件之间的通信了。

# 渲染组件 render 方法

Vue 的 render 方法是用来渲染组件的函数,它可以用来替代模板语法,通过代码的方式来生成 DOM 结构。相较 于模板语法,render 方法具有更好的类型检查和代码提示。

下面详细介绍 Vue 的 render 方法的使用方法:

4.1 基本语法

render 方法的基本语法如下

render: function (createElement) {
  // 返回一个 VNode
}
1
2
3

其中 createElement 是一个函数,它用来创建 VNode(虚拟节点),并返回一个 VNode 对象。

4.2 创建 VNode

要创建 VNode,可以调用 createElement 函数,该函数接受三个参数:

标签名或组件名

可选的属性对象

子节点数组

例如,下面的代码创建了一个包含文本节点的 div 元素

render: function (createElement) {
  return createElement('div', 'Hello, world!')
}
1
2
3

如果要创建一个带有子节点的元素,可以将子节点作为第三个参数传递给 createElement 函数。

例如,下面的代码创建了一个包含两个子元素的 div 元素

render: function (createElement) {
  return createElement('div', [
    createElement('h1', 'Hello'),
    createElement('p', 'World')
  ])
}
1
2
3
4
5
6

如果要给元素添加属性,可以将属性对象作为第二个参数传递给 createElement 函数。

例如,下面的代码创建了一个带有样式和事件处理程序的 button 元素

render: function (createElement) {
  return createElement('button', {
    style: { backgroundColor: 'red' },
    on: {
      click: this.handleClick
    }
  }, 'Click me')
},
methods: {
  handleClick: function () {
    console.log('Button clicked')
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

4.3 动态数据

render 方法可以根据组件的状态动态生成内容。要在 render 方法中使用组件的数据,可以使用 this 关键字来 访问组件实例的属性。

例如,下面的代码根据组件的状态动态生成了一个带有计数器的 div 元素

render: function (createElement) {
  return createElement('div', [
    createElement('p', 'Count: ' + this.count),
    createElement('button', {
      on: {
        click: this.increment
      }
    }, 'Increment')
  ])
},
data: function () {
  return {
    count: 0
  }
},
methods: {
  increment: function () {
    this.count++
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

4.4 JSX

在使用 Vue 的 render 方法时,也可以使用 JSX(JavaScript XML)语法,这样可以更方便地编写模板。要使用 JSX,需要在组件中导入 Vue 和 createElement 函数,并在 render 方法中使用 JSX 语法。

例如,下面的代码使用了 JSX 语法来创建一个计数器组件

import Vue from 'vue'

export default {
  render() {
    return (
      <div>
        <p>Count:{this.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    )
  },
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注意,在使用 JSX 时,需要使用 {} 包裹 JavaScript 表达式。

4.5 生成函数式组件

除了生成普通的组件,render 方法还可以生成函数式组件。函数式组件没有状态,只接收 props 作为输入,并返 回一个 VNode。因为函数式组件没有状态,所以它们的性能比普通组件更高。

要生成函数式组件,可以在组件定义中将 functional 属性设置为 true。

例如,下面的代码定义了一个函数式组件,用于显示列表项

export default {
  functional: true,
  props: ['item'],
  render: function (createElement, context) {
    return createElement('li', context.props.item)
  }
}
1
2
3
4
5
6
7

注意,在函数式组件中,props 作为第二个参数传递给 render 方法。

知识汇总   |