vue3.0入门
1.安装新版本vue
npm install -g @vue/cli
2.查看版本
vue --version
3.项目初始化
vue create cli3-test //vue create [项目名称]
main.js文件
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
router.js路由文件
// 可以根据路由模式的不同,后面俩可以只引用一个
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home.vue'
// 构建我们的页面路由配置,可以看到,这里和原来的写法并无二致。
const routes = [
{
path: '/',
component: Home
}, {
path: '/about',
component: () => import('@/views/About.vue'),
}
]
const router = createRouter({
// 使用 hash 模式构建路由( url中带 # 号的那种)
history: createWebHashHistory(),
// 使用 history 模式构建路由 ( url 中没有 # 号,但生产环境需要特殊配置)
// history: createWebHistory(),
routes
})
export default router
得益于 vue3.0 的特性,我们现在不比把组件内容全部包裹在某一个 div 下面了,一个 template 里面可以有多个根节点元素
App.vue
<template>
<router-view />
</template>
About.vue
<template>
这里是关于我们的页面
<router-link to="/">点这里去首页</router-link>
</template>
在main.js挂载
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 将创建的 App 搞个别名
const app = createApp(App)
// 使用路由配置
app.use(router)
// 挂载运行
app.mount('#app')
4.setup()函数
有两个参数:== props == 、== context ==
** 在 setup 函数中 return 出去的东西,可以在模板区域直接使用,也不必理会 this **
1)props
// MyBook.vue
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
// WARNING
// 因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性
// 如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作:
// About.vue
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
2)context
// About.vue
export default {
setup(props, context) {
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
}
}
// About.vue
// 不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
5.ref
// Home.vue
<template>
<router-link to="/about">点这里去关于我们页面</router-link>
<div class="home">
这里是一个计数器 >>> <span class="red">{{count}}</span> <br>
<button @click="countAdd">{{btnText}}</button>
</div>
</template>
<script>
// ref 是 vue 3.0 的一个重大变化,其作用为创建响应式的值
import { ref } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
setup () {
// 定义一个不需要改变的数据
const btnText = '点击按钮'
// 定义一个 count 的响应式数据,并赋值为 0
const count = ref(0)
// 定义一个函数,修改 count 的值。
const countAdd = () => {
count.value++
}
// 导出一些内容给上面的模板区域使用
return {
btnText,
count,
countAdd
}
}
}
</script>
<style lang="scss">
.home {
line-height: 2;
.red {
color: red;
}
}
</style>
unref
如果参数是一个 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 的语法糖函数。
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // unwrapped 现在一定是数字类型
}
toRef
可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}
toRefs
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
// ref 和原始 property 已经“链接”起来了
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
toRefs 只会为源对象中包含的 property 生成 ref。如果要为特定的 property 创建 ref,则应当使用 toRef
isRef
检查值是否为一个 ref 对象。
customRef
<input v-model="text" />
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello')
}
}
}
shallowRef
const foo = shallowRef({})
// 改变 ref 的值是响应式的
foo.value = {}
// 但是这个值不会被转换。
isReactive(foo.value) // false
triggerRef
const shallow = shallowRef({
greet: 'Hello, world'
})
// 第一次运行时记录一次 "Hello, world"
watchEffect(() => {
console.log(shallow.value.greet)
})
// 这不会触发副作用,因为 ref 是浅层的
shallow.value.greet = 'Hello, universe'
// 记录 "Hello, universe"
triggerRef(shallow)
6.reactive
reactive 和 ref 的区别就是,reactive 是处理对象或者数组的
<template>
<router-link to="/">点这里去首页</router-link>
<hr>
<dl>
<dt>{{state.name}}</dt>
<dd>性别:{{state.sex}}</dd>
<dd>地址:{{state.address}}</dd>
</dl>
<button @click="addressChange">更新地址</button>
</template>
<script>
// reactive 是 vue 3.0 的一个重大变化,其作用为创建响应式的对象或数组
import { reactive } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
setup () {
// 定义一个 state 的响应式对象数据,并赋值
const state = reactive({
name: 'FungLeo',
sex: 'boy',
address: '上海'
})
console.log(state)
// 定义一个函数,修改 state 的值。
const addressChange = () => {
state.address += '浦东'
}
// 导出一些内容给上面的模板区域使用
return {
state,
addressChange
}
}
}
</script>
7.生命周期函数
2.0 | 3.0 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
// 你需要使用到什么生命周期,就引出来什么生命周期
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
ref
} from 'vue'
export default {
// setup 函数,就相当于 vue 2.0 中的 created
setup () {
const count = ref(0)
// 其他的生命周期都写在这里
onBeforeMount (() => {
count.value++
console.log('onBeforeMount', count.value)
})
onMounted (() => {
count.value++
console.log('onMounted', count.value)
})
// 注意,onBeforeUpdate 和 onUpdated 里面不要修改值,会死循环的哦!
onBeforeUpdate (() => {
console.log('onBeforeUpdate', count.value)
})
onUpdated (() => {
console.log('onUpdated', count.value)
})
onBeforeUnmount (() => {
count.value++
console.log('onBeforeUnmount', count.value)
})
onUnmounted (() => {
count.value++
console.log('onUnmounted', count.value)
})
// 定义一个函数,修改 count 的值。
const countAdd = () => {
count.value++
}
return {
count,
countAdd
}
}
}
8.Provide / Inject
只能在当前活动实例的 setup() 期间调用
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
provide: {
location: 'North Pole',
geolocation: {
longitude: 90,
latitude: 135
}
}
}
</script>
<!-- src/components/MyMarker.vue -->
<script>
export default {
inject: ['location', 'geolocation']
}
</script>
provide
provide 函数允许你通过两个参数定义 property:
- name ( 类型)
- value
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
provide('location', 'North Pole')
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
}
</script>
Inject
inject 函数有两个参数:
- 要 inject 的 property 的 name
- 默认值 (可选)
<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
return {
userLocation,
userGeolocation
}
}
}
</script>
响应性
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
provide('location', location)
provide('geolocation', geolocation)
}
}
</script>
<!-- 现在,如果这两个 property 中有任何更改,MyMarker 组件也将自动更新!-->
<!-- src/components/MyMap.vue -->
<!-- 提供 -->
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', location)
provide('geolocation', geolocation)
provide('updateLocation', updateLocation)
}
}
</script>
<!-- src/components/MyMarker.vue -->
<!-- 接收 -->
<script>
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
const updateUserLocation = inject('updateLocation')
return {
userLocation,
userGeolocation,
updateUserLocation
}
}
}
</script>
readonly
__ 如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly __
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, readonly, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', readonly(location))
provide('geolocation', readonly(geolocation))
provide('updateLocation', updateLocation)
}
}
</script>
9.计算属性
<template>
<router-link to="/">点这里去首页</router-link>
<hr>
<div class="home">
这里是一个计数器 >>> <span class="red">{{count}}</span> <br>
右边的数字是上面的数字的十倍 >>> <span class="red">{{bigCount}}</span> <br>
右边的数字是上面的数字的一百倍 >>> <span class="red">{{computeCount['100x']}}</span> <br>
右边的数字是上面的数字的一千倍 >>> <span class="red">{{computeCount['1000x']}}</span> <br>
<button @click="countAdd">点这个按钮上面的数字会变</button>
</div>
</template>
<script>
// 需要使用计算属性,也需要从 vue 中导出引入
import { ref, computed } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
setup () {
// 定义一个 count 的响应式数据,并赋值为 0
const count = ref(0)
// 定义一个函数,修改 count 的值。
const countAdd = () => {
count.value++
}
// 计算属性,使用计算函数并命名,然后在 return 中导出即可
const bigCount = computed(() => {
return count.value * 10
})
// 计算多个属性,可以通过返回一个对象的方式来实现
const computeCount = computed(() => {
return {
'100x': count.value * 100,
'1000x': count.value * 1000,
}
})
// 导出一些内容给上面的模板区域使用
return {
count,
countAdd,
bigCount,
computeCount
}
}
}
</script>
10.watch
3 个参数:
- 一个想要侦听的响应式引用或 getter 函数
- 一个回调
- 可选的配置选项
import { ref, watch } from 'vue'
const counter = ref(0)
watch(counter, (newValue, oldValue) => {
console.log('The new counter value is: ' + counter.value)
})
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs } from 'vue'
// 在我们组件中
setup (props) {
// 使用 `toRefs` 创建对prop的 `user` property 的响应式引用
const { user } = toRefs(props)
const repositories = ref([])
const getUserRepositories = async () => {
// 更新 `prop.user` 到 `user.value` 访问引用值
repositories.value = await fetchUserRepositories(user.value)
}
onMounted(getUserRepositories)
// 在 user prop 的响应式引用上设置一个侦听器
watch(user, getUserRepositories)
return {
repositories,
getUserRepositories
}
}
watch重点为了监听做事情. 看重的不是返回结果, 而是属性的变化.
computed重点为了得到一个属性值,看重的是它的返回结果.