【细节】Vue3基本使用笔记

vite

文档:https://cn.vitejs.dev/guide/

安装:

使用 NPM:

$ npm create vite@latest

使用 Yarn:

$ yarn create vite

使用 PNPM:

$ pnpm create vite

选择项目名称:? Project name: » vite-project

选择框架:? Select a framework: » - Use arrow-keys. Return to submit.

Vanilla
Vue
React
Preact
Lit
Svelte
Others

配置eslint

官网:https://github.com/eslint/eslint

安装:npm init @eslint/config

配置:

√ How would you like to use ESLint? · style
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · No / Yes  No
√ Where does your code run? · browser
√ How would you like to define a style for your project? · guide
√ Which style guide do you want to follow? · standard
√ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-standard@latest
The config that you've selected requires the following dependencies:

eslint-plugin-vue@latest eslint-config-standard@latest eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0
√ Would you like to install them now? · No / Yes  Yes
√ Which package manager do you want to use? · yarn

认识vue3.0生命周期钩子函数

  • setup 创建实例前
  • onBeforeMount 挂载DOM前
  • onMounted 挂载DOM后
  • onBeforeUpdate 更新组件前
  • onUpdated 更新组件后
  • onBeforeUnmount 卸载销毁前
  • onUnmounted 卸载销毁后
<script setup>
// setup 这个函数替代了beforeCreate、created生命周期函数
import { onMounted } from 'vue'
const PI = 3.1414926

onMounted(() => {
  console.log('组件挂载之后')
})
</script>

setup的细节

setup执行的时机

  • beforeCreate之前执行(一次), 一旦props被解析就会执行setup,此时组件对象还没有创建
  • thisundefined, 不能通过this来访问data/computed/methods / props
  • 其实所有的composition API相关回调函数中也都不可以

setup的返回值

  • 一般都返回一个对象: 为模板提供数据, 也就是模板中可以直接使用此对象中的所有属性/方法
  • 返回对象中的属性会与data函数返回对象的属性合并成为组件对象的属性
  • 返回对象中的方法会与methods中的方法合并成功组件对象的方法
  • 如果有重名, setup优先

注意:

  • 一般不要混合使用: methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问datamethods
  • setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性数据

setup的参数

  • props: 包含props配置声明且传入了的所有属性的对象
  • attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs
  • slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots
  • emit: 用来分发自定义事件的函数, 相当于 this.$emit

ref

    {{ PI }}
    <button @click="change">改变数据</button>
    <ul>
      <li v-for="user in userlist" :key="user.name">{{ user.name }}</li>
    </ul>
    <button @click="adduser">添加学员</button>
import { ref } from 'vue'
//创建一个响应式的数据 ref可以创建任何类型的数据
const PI = ref(3.1414926)
const change = () => {
  //ref创建的数据,只能通过.value来修改
  PI.value = 3.14
}
const userlist = ref([
  { name: "张三", age: 18 },
  { name: "李四", age: 19 },
  { name: "王五", age: 20 },
]);
const adduser = () => {
  userlist.value.push({ name: "赵六", age: 21 });
};

reactive

    <div>
      {{ student.name }} {{ student.age }}
      <button @click="updatestu">修改学员</button>
    </div>
    <div>
      {{ nameref }} {{ ageref }}
      <button @click="updatename">更新结构出来的name</button>
    </div>
import { reactive } from 'vue'
// reactive创建的响应式数据是一个对象 可以直接修改对象的属性
let student = reactive({
  name: '张三',
  age: 18,
})
const updatestu = () => {
  student.name = '李四'
  console.log(student)
}
// 注意:1.reactive创建的对象 如果把对象里面的属性结构出来 他们就不是响应式的了
//      2.如果用一个新的响应式对象 替换掉原来的对象 也会导致结构出来的属性不是响应式的
let { name, age } = student
const updatename = () => {
  name = '王五'
  student = reactive({
    name: '赵六',
    age: 18,
  })
}
//如果想要结构出来的属性是响应式的 需要用toRef()包裹一下
const nameref = toRefs(student,'name');
const ageref = toRefs(student,'age')
const updatename = () => {
  nameref.value = "王五";
  ageref.value = 99
};
//转换响应式对象中所有属性为单独响应式数据
import { toRefs } from "vue";
const studentrefs = toRefs(student);
const updatename = () => {
  studentrefs.age.value = 100
};

computed计算属性

<template>
  <div>
    {{age}}==>{{age2}}
    <button @click="handleAdd">age+1</button>
    <div>{{fullName}}</div>
    <button @click="changeName">改变成李四</button>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
const age = ref(17)
const handleAdd = () => {
  age.value++
}
const age2 = computed(() =>
  age.value >= 18 ? '成年' : '未成年'
)

const firstName = ref('张')
const lastName = ref('三')
const fullName = computed({
  get () {
    return firstName.value + lastName.value
  },
  set (value) {
    const names = value.split(' ')
    firstName.value = names[0]
    lastName.value = names[1]
  }
})
const changeName = function () {
  fullName.value = '李 四'
}
</script>

watch监听

1.监听单个的ref

如果ref是简单数据类型,要加value,复杂数据类型不用加

const user = ref({
  username: 'jack',
  age: 19,
  pet: {
    name: '小花',
    age: 2
  }
})
const changeUser = function () {
  user.value.pet.name = 'xiaohei'
}

watch(user.value, (newVal) => {
  console.log('user发生了变化', newVal)
})

2.监听多个数据组成的数组,参数的顺序需要和数组中的顺序一致

watch([firstName, lastName], ([newFirstName, newLastName]) => {
  fullName.value = newFirstName + newLastName
})

3.监听getter函数

watch(
  () => firstName.value + lastName.value,
  (newVal) => {
    fullName.value = newVal
  }
)

特别注意

4.监听reactive创建的响应式对象

会隐式创建一个深度监听器。不管嵌套数据的哪一层发生变化,回调函数都会执行

const person = reactive({
  username: 'jack',
  age: 18,
  sex: '男',
  pet: {
    name: '小花',
    age: 2
  }
})

const change = function () {
  person.pet.name = 'xiaohei'
}

watch(person, (newVal) => {
  console.log('person发生了变化', newVal)
})

// 只监听reactive创建的响应式对象的某个属性呢?==> 改为getter函数的写法(不然就监听person整体)
watch(
  () => person.pet,
  (newVal) => {
    console.log('person发生了变化', newVal)
  },
  { deep: true } 

//当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用 { deep: true } 强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。

总结:reactive监听整体,自动深度监听;监听某个属性需要用getter函数并使用{ deep: true } 进入深度监听

5.监听props

  • watch监听 props 中的基本类型数据,需要通过 getter 函数返回值的形式(()=>props.xxx)才能监听

  • watch监听 props 中的引用类型数据,且父组件中没有改变地址指向时,可以直接监听

  • watch监听 props 中的引用类型数据,且父组件中改变了地址指向时,需要通过 getter 函数返回值的形式(()=>props.xxx)才能监听

获取dom元素

<template>
  <div>
    <div ref="divRef">hello</div>
    <button @click="getDom">点击获取dom元素</button>
    <ul>
      <!-- 如果ref用在v-for上面 这里获取的是dom元素组成的一个数组 -->
      <li v-for="item in 6" :key="item" ref="liRef">{{item}}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'
// 这里的dom元素获取 这个ref的变量必须和template中的ref的值一致
const divRef = ref(null)
const liRef = ref(null)
const getDom = function () {
  console.log(divRef.value)
  console.log(liRef.value)
}
</script>
获取组件内部的数据
<template>
  <!-- 注意:组件上的ref 在使用了<script setup>的组件时组件内部的东西是私有的 -->
  <!-- 如果想要使用通过组件defineExpose向外暴露数据 -->
  <TestView ref="testRef"></TestView>
  <button @click="getDom">点击获取dom元素</button>
</template>

<script setup>
import { ref } from 'vue'
import TestView from './TestView.vue'
// 这里的dom元素获取 这个ref的变量必须和template中的ref的值一致
const testRef = ref(null)
const getDom = function () {
  console.log(testRef.value.num)
  testRef.value.add(2)
}
</script>
    <!-- 组件 -->
<template>
  <div>
    <div>{{num}}</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const num = ref(0)
const add = (n) => {
  num.value += n
}
// 向外暴露数据
defineExpose({
  num,
  add
})
</script>

父子通信

<!-- 父组件 -->
<template>
  <div>
    father 有{{money}}元 儿子考了{{sonScore}}分
    <SonView :Fathermoney="money" @tellFather="getScore"></SonView>
  </div>
</template>

<script setup>
import SonView from './SonView.vue'
import { ref } from 'vue'
const money = ref(100)
const sonScore = ref('???')
const getScore = (score) => {
  sonScore.value = score
}
</script>


<!-- 子组件 -->
<template>
  <div>
    son 有父亲的{{Fathermoney}}元
    <button @click="getProps">通过js获取props</button>
    <button @click="handelscore">点击告诉父亲分数{{score}}</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
// 子组件中,使用defineProps定义props
// defineProps(['Fathermoney'])
// 如果想要通过js获取属性值 需要一个返回值来接收属性值
// 注意这里是返回值是只读属性 不能修改
const props = defineProps({
  Fathermoney: {
    type: Number,
    default: 0
  }
})

const getProps = () => {
  console.log('通过js获取props', props.Fathermoney)
}
// 子组件中,使用defineEmit定义emit
const emit = defineEmits(['tellFather'])
const score = ref(99)
const handelscore = () => {
  emit('tellFather', score.value)
}
</script>

provide依赖注入数据

<!--父组件也可以是爷爷组件 -->
<script setup>
import { provide } from 'vue'
provide('msg', 'hello world')
</script>

<!--子组件 -->
<template>
  <div>
    <div>{{msg}}</div>
  </div>
</template>

<script setup>
import { inject } from 'vue'
// 使用inject获取provide的提供的数据
const msg = inject('msg')
</script>

V-model语法糖

方法一:

  1. 将内部原生 元素的 value attribute 绑定到 modelValue prop
  2. 当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件
 <!-- App组件 -->
<script setup>
import { ref } from 'vue'
import VmodelView from './components/VmodelView.vue'
const searchText = ref('sss')
</script>
<template>
  <VmodelView v-model="searchText"></VmodelView>
  <!-- 上面的写法是下面的这种写法的语法糖 -->
  <VmodelView :model-value="searchText" @update:model-value="newV=>searchText=newV">
  </VmodelView>
</template>

  <!-- VmodelView组件 -->
<template>
  <div>
    <input type="text" placeholder="请输入内容" @input="handleinput" :value="modelValue">
  </div>
</template>

<script setup>
defineProps({
  // 定义modelValue属性 默认固定的 不能乱写
  modelValue: {
    type: String,
    default: ''
  }
})
// 发送事件的名称也是固定的 不能乱写
const emit = defineEmits(['update:modelValue'])
const handleinput = (e) => {
  emit('update:modelValue', e.target.value)
}
</script>

<style lang="scss" scoped>

</style>

方法二:

使用一个可写的,同时具有 getter 和 setter 的 computed 属性。get 方法需返回 modelValue prop,而 set 方法需触发相应的事件

<!-- CustomInput.vue -->
<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  }
})
</script>

<template>
  <input v-model="value" />
</template>

多个v-model的绑定:

import VmodelMany from './components/VmodelMany.vue'
const username = ref('admin')
const pwd = ref('123456')
<VmodelMany v-model:username="username" v-model:pwd="pwd"></VmodelMany>


 <input type="text" :value="username" placeholder="用户名" @input="handleusername">
 <input type="text" :value="pwd" placeholder="密码" @input="handlepwd">
 // 多个v-model的写法
defineProps({
  username: {
    type: String,
    default: ''
  },
  pwd: {
    type: String,
    default: ''
  }
})
const emit = defineEmits(['update:username', 'update:pwd'])
const handleusername = (e) => {
  emit('update:username', e.target.value)
}
const handlepwd = (e) => {
  emit('update:pwd', e.target.value)
}

自定义指令

<template>
  <div>
    <h2>DirectiveView</h2>
    <input type="text" v-focus>
  </div>
</template>

<script setup>
// 自定义指令 通过一个对象创建这个对象必须是以v开头
const vFocus = {
  // 指令的钩子函数
  mounted (el) {
    el.focus()
  }
}
</script>

组合式函数

我们想在多个组件中复用这个相同的逻辑 我们可以把这个逻辑以一个组合式函数的形式提取到外部文件中:

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

// 按照惯例,组合式函数名以“use”开头
export 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 }
}

下面是它在组件中使用的方式:

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

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

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

更多详情可见:https://vuejs.org/

码字不易,望各位未来大牛点赞支持一波~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值