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,此时组件对象还没有创建
-
this
是undefined
, 不能通过this
来访问data
/computed
/methods
/ props
- 其实所有的
composition API
相关回调函数中也都不可以
setup
的返回值
- 一般都返回一个对象: 为模板提供数据, 也就是模板中可以直接使用此对象中的所有属性/方法
- 返回对象中的属性会与
data
函数返回对象的属性合并成为组件对象的属性
- 返回对象中的方法会与
methods
中的方法合并成功组件对象的方法
- 如果有重名,
setup
优先
注意:
- 一般不要混合使用:
methods
中可以访问setup
提供的属性和方法, 但在setup
方法中不能访问data
和methods
-
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语法糖
方法一:
- 将内部原生 元素的 value attribute 绑定到 modelValue prop
- 当原生的 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/
码字不易,望各位未来大牛点赞支持一波~