vue-next 2020年09月18日,正式发布vue3.0版本。但是由于刚发布周边生态不支持,大多数开发者处于观望。
Vue3优点:
现在公司90%还是vue2.0,新的项目可能会采用3.0
vite是什么:官方文档
vite基本使用:
npm init vite-app 项目名称
或者 yarn create vite-app 项目名称
npm i
或者 yarn
npm run dev
或者 yarn dev
<script type="module" src="/src/main.js"></script>
//浏览器就会像服务器发起一个GET http://localhost:3000/src/main.js请求main.js文件:
// /src/main.js:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
GET http://localhost:3000/@modules/vue.js
GET http://localhost:3000/src/App.vue
Vite
的主要功能就是通过劫持浏览器的这些请求,并在后端进行相应的处理将项目中使用的文件通过简单的分解与整合,然后再返回给浏览器,vite整个过程中没有对文件进行打包编译,所以其运行速度比原始的webpack
开发编译速度快出许多!全局安装yarn
npm init vite-app vue3-demo(项目名)
进入到项目
cd vue3-demo
装包
npm i/ yarn
运行
npm run dev
main.js 入口代码
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
// 创建vue应用并渲染App组件,挂载到#app容器中
createApp(App).mount('#app')
vue2.0采用的叫做选项式api:
例如我们想实现某一个功能,关于这个功能的数据我们会定义在data中,事件函数定义在methods中,计算属性定义在computed中...
new Vue({
data () {
return {
a: 213,
b: 2,
c: 5,
d: 6
}
},
methods: {
add () {},
remove () {}
},
computed: {
totalPrice () {}
}
})
实际上我们想实现一个功能会把我们代码拆分写到不同的模块中,这样我们很难区分,哪个数据和哪个逻辑是一一对应的,而且想实现这个功能也要在data、methods、computed中跳来跳去。
Vue3.0的组合式(composition-api)api:
我们会把同一功能的逻辑写在一起
<script>
export default {
name: 'App',
setup() {
// 添加功能
const a = 1
const add = () => {}
// 删除功能
const b = 2
const remove = () => {}
}
}
</script>
setup是composition-api的入口函数
在生命周期beforeCreate之前被调用
setup内部不能使用this获取到组件实例
setup内部可以返回数据和方法供模版使用
<template>
<h1>{{ count }}</h1>
<button @click="clickHandle">点击事件</button>
</template>
<script>
export default {
name: 'App',
beforeCreate () {
console.log(123)
},
setup() {
const count = 10
const clickHandle = () => {
console.log('点我了')
}
return {
count,
clickHandle
}
}
}
</script>
⚠️:setup内部直接定义的数据不是响应式的
可以将一个复杂数据类型代理为响应式数据
引入reactive
import { reactive } from 'vue'
通过reactive定义响应式数据
setup() {
// 定义响应式数据
const data = reactive({
count: 10
})
const clickHandle = () => {
// 修改数据
data.count++
}
return {
data,
clickHandle
}
}
模版中使用响应式数据
{{ data.count }}
将响应式对象中某一个属性结构成响应式数据
直接结构无法达成响应式
<template>
<h1>用户:{{ name }}</h1>
<button @click="clickHandle">修改姓名</button>
</template>
setup() {
const state = reactive({
name: '张三',
age: 19
})
let { name } = state
const clickHandle = () => {
name = '李四'
}
return {
name,
clickHandle
}
}
利用toRef进行处理
setup() {
const state = reactive({
name: '张三',
age: 19
})
let name = toRef(state, 'name')
const clickHandle = () => {
// 需要通过value访问到具体数据
name.value = '李四'
}
return {
name,
clickHandle
}
}
将响应对象内所有属性处理为响应式属性
<template>
<h1>用户:{{ name }}</h1>
<button @click="clickHandle">修改姓名</button>
</template>
setup() {
const state = reactive({
name: '张三',
age: 19
})
const clickHandle = () => {
console.log(123)
state.name = '李四'
}
return {
...toRefs(state),
clickHandle
}
}
常用语将普通数据处理为响应式数据
引入ref
import { ref } from 'vue'
通过ref定义响应式数据
setup() {
// ref函数可传递数据的默认值
const count = ref(10)
return {
count
}
}
使用数据
<template>
<h1>{{ count }}</h1>
<button @click="clickHandle">修改count</button>
</template>
修改数据(需要通过数据.value进行修改)
setup() {
const count = ref(10)
const clickHandle = () => {
count.value++
}
return {
count,
clickHandle
}
}
可以直接导入 onXXX
一族的函数来注册生命周期钩子:
import { onUpdated, onUnmounted } from 'vue'
export default {
name: 'App',
setup() {
onBeforeMount(() => {
console.log(document.querySelector('#custom-h1')) // null
})
onMounted(() => {
console.log(document.querySelector('#custom-h1')) // <h1 id="custom-h1">hello</h1>
})
}
}
与 2.x 版本生命周期相对应的组合式 API
beforeCreate
-> 使用 setup()
created
-> 使用 setup()
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeDestroy
-> onBeforeUnmount
destroyed
-> onUnmounted
案例分析:
<template>
<h1>鼠标的X:{{ x }}</h1>
<h1>鼠标的Y:{{ y }}</h1>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'App',
setup() {
const mouse = reactive({
x: 0,
y: 0
})
return mouse
}
}
</script>
import { reactive, toRefs, onMounted } from 'vue'
export default {
name: 'App',
setup() {
// 定义数据
const mouse = reactive({
x: 0,
y: 0
})
// 鼠标移动修改数据
const setDataOnMove = e => {
console.log(e)
}
// 绑定鼠标事件
onMounted(() => {
document.addEventListener('mousemove', setDataOnMove)
})
return mouse
}
}
// 鼠标移动修改数据
const setDataOnMove = e => {
mouse.x = e.x
mouse.y = e.y
}
// 1.4 组件消耗,删除事件
onUnmounted(()=>{
document.removeEventListener('mousemove', move)
})
引入computed
直接在setup内部定义
<template>
<h1>粉丝数量:{{ formatFans }}</h1>
</template>
<script>
import { computed, ref } from 'vue'
export default {
name: 'App',
setup() {
const fans = ref(189987)
// 利用计算属性进行计算
const formatFans = computed(() => {
return ((fans.value)/10000).toFixed(2) + '粉丝'
})
return {
fans,
formatFans
}
}
}
</script>
在reactive中定义
<template>
<h1>粉丝数量:{{ formatFans }}</h1>
</template>
<script>
import { computed, reactive } from 'vue'
export default {
name: 'App',
setup() {
const state = reactive({
fans: 189976,
formatFans: computed(() => {
return (state.fans / 10000).toFixed(2) + '万'
})
})
return state
}
}
</script>
数据监视
<template>
<h1>国籍: {{ nationality }}</h1>
<button @click="setNationnality">修改国籍</button>
</template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup() {
// 定义数据
const nationality = ref('美国')
// 修改数据
const setNationnality = () => {
nationality.value = '中国'
}
// 监视数据
watch(nationality, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
return {
nationality,
setNationnality
}
}
}
</script>
<template>
<h1>姓名: {{ person.name }}</h1>
<h1>年龄 {{ person.age }}</h1>
<button @click="setPersonName">修改姓名</button>
</template>
<script>
import { reactive, watch } from 'vue'
export default {
name: 'App',
setup() {
// 定义数据
const person = reactive({
name: '张三',
age: 19
})
// 修改数据
const setPersonName = () => {
person.name = '李四'
}
// 监视数据
watch(person, (newVal, oldVal) => {
console.log(newVal.name, oldVal.name) // 监视的是一个对象 newVal = oldVal
})
return {
person,
setPersonName
}
}
}
</script>
// 监视某个属性
watch(() => person.name, (newVal, oldVal) => {
// 监视的是一个对象 newVal = oldVal
console.log('person的name那么变化了')
})
<template>
<h1>国籍: {{ nationality }}</h1>
<button @click="setNationnality">修改国籍</button>
<h1>姓名: {{ person.name }}</h1>
<h1>年龄 {{ person.age }}</h1>
<h1>儿子:{{ person.child[0] }}</h1>
<h1>儿子:{{ person.child[1] }}</h1>
<button @click="setPersonName">修改姓名</button>
<button @click="setPersonAge">修改年龄</button>
<button @click="setPersonChildName">修改小儿子的名字</button>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup() {
// 定义数据
const person = reactive({
name: '张三',
age: 19,
child: [
'张小三',
'张老三'
]
})
const setPersonChildName = () => {
person.child[0] = '王小三'
}
// 监视复杂数据类型中的某个复杂数据类型
watch(() => person.child, (newVal, oldVal) => {
// 监视的是一个对象 newVal = oldVal
console.log('person的儿子的name那么变化了')
}, {
deep: true, // 深度监听
immediate: true // 默认触发一次
})
return {
person,
setPersonChildName
}
}
}
</script>
// 监视多个数据
watch([person, nationality], (newVal, oldVal) => {
console.log(newVal[1])
console.log(oldVal[1])
console.log('person或者nationnality变化了')
})
定义一个空的响应式数据为了和某个dom或组件进行绑定
import { onMounted, ref } from 'vue'
export default {
name: 'App',
setup() {
// 通过ref定义响应式数据
const h1 = ref(null)
// 在onMounted操作dom
onMounted(() => {
console.log(h1.value)
})
return {
h1
}
}
}
将响应式数据在模版中将某个dom或组件通过ref进行绑定
注意:不需要动态绑定
<h1 ref="h1">hello</h1>
父组件通过属性绑定传动
<template>
<h1>父组件的钱: {{ money }}</h1>
<child-a :money="money"></child-a>
</template>
<script>
import { ref } from 'vue'
import ChildA from './components/child-a.vue'
export default {
name: 'App',
setup() {
const money = ref(1000000)
return {
money
}
},
components: {
ChildA
}
}
</script>
子组件通过props接收
<template>
<h1>子组件的钱: {{ money }}</h1>
</template>
<script>
export default {
name: 'child-a',
props: {
money: {
type: Number,
required: true
}
},
setup() {
return {
}
}
}
</script>
子组件也可以通过setup行参获取到
setup(props) {
console.log(props.money)
return {
}
}
子组件通过context.emit触发自定义事件
<template>
<h1>子组件的钱: {{ money }}</h1>
<button @click="subMoney">花了50</button>
</template>
<script>
export default {
name: 'child-a',
props: {
money: {
type: Number,
required: true
}
},
setup(props, context) {
// context 是一个普通的 JavaScript 对象,它暴露组件的三个 property
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
const subMoney = () => {
context.emit('change-money', -50)
}
return {
subMoney
}
}
}
</script>
父组件通过定义自定义事件的函数接收数据,并处理业务逻辑
<template>
<h1>父组件的钱: {{ money }}</h1>
<!-- 定义自定义事件 -->
<child-a :money="money" @change-money="changeMoney">
</child-a>
</template>
<script>
import { ref } from 'vue'
import ChildA from './components/child-a.vue'
export default {
name: 'App',
setup() {
let money = ref(1000000)
// 通过事件函数的行参获取到子组件传递过来的数据
const changeMoney = newMoney => {
console.log(newMoney)
money.value += newMoney
}
return {
money,
changeMoney
}
},
components: {
ChildA
}
}
</script>
警告说明:我们需要告知组件哪些是自定义事件
Extraneous non-emits event listeners (changeMoney) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits"
在子组件内部定义emits
name: 'App',
emits: ['change-money']
依赖注入并不是vue3.0新增的特性,2.0就开始支持,只不过使用方式有所区别
传数据
引入provide进行提供数据
import { provide } from 'vue'
setup () {
const money = ref(10000)
provide('money', money)
return {
money
}
}
子组建、孙子组件通过inject进行接收
import { inject } from 'vue'
export default {
setup() {
const money = inject('money')
return {
money
}
}
}
父组件传方法供子组件调用修改数据
提供方法
setup () {
let money = ref(10000)
// 修改money数据
const setMoney = newMoney => {
money.value = newMoney
}
provide('money', money)
// 提供方法
provide('setMoney', setMoney)
return {
money
}
}
子组件消费
<template>
<h1>孙子:{{ money }}</h1>
<button @click="clickHandle">改money</button>
</template>
<script>
import { inject } from 'vue'
export default {
name: 'App',
setup() {
const money = inject('money')
// 获取provide提供的方法
const setMoney = inject('setMoney')
const clickHandle = () => {
// 点击调用
setMoney(10)
}
return {
money,
clickHandle
}
}
}
</script>
vue3中的路由使用方式变成了导入方法,进行路由的使用
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
createRouter: 用来创建路由对象
createWebHistory:用来使用history模式的路由
createWebHashHistory:用来使用hash模式的路由
使用useRouter进行编程式导航
import { useRouter } from 'vue-router'
setup () {
const router = useRouter()
const goHome = () => {
router.push('/home')
}
}
通过useRoute获取当前路由信息,path、query、params
import { useRoute } from 'vue-router'
setup () {
const route = useRoute()
console.log(route.path)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。