start
Vue3 has been out for some time. Recently, the company has a project that needs to be reconstructed, and I reconstructed it once with Vue3. Personally, I think the changes are not very big in terms of development experience, but I have to brag that Vite is really fast, and THERE are many problems in the development process, especially when deploying, without carefully reading the documents, it will be GG. Let’s cut to the chase.
The project architecture
- vue3.0.5
- Axios 0.21.1
- Element – plus 1.0.2 – beta. 35
- Vue – the router 4.5.5
- Vuex: 4.0.0
instructions
This article mainly introduces some relevant comparisons between Vue2 and Vue3. There are many documents about basic knowledge such as REF and Reactive. You can get started in about 10 minutes by checking relevant documents of other big players.
Vue3 new syntax sugar script setup
<template>
<panel class="size-wrapper">This is the home page<template #footer class="dialog-footer">
<el-button type="primary" @click="onConfirmClick()">Know the</el-button>
</template>
</panel>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import Panel from '@/components/Panel.vue'
</srcipt>
Copy the code
- Add setup properties directly to script tags, rather than return a bunch of properties at the bottom like the old syntax
- Component import is used directly in template without registration
- This syntax feels like a lot less code, but large files can be messy. I prefer this syntax, but it depends on the project.
- Script Setup related documents
Data attributes and methods
// vue2
data() {
return {
loading: false.tableData: []}}, methods: {getList(){
this.loading = true
this.tableData = []
this.loading = false}}Copy the code
// vue3
<script setup>
import { ref, reactive } from 'vue'
let state = reactive({
loading: false.tableData: []})function getList(){
state.loading = true
state.tableData = []
state.loading = false
}
</srcipt>
Copy the code
- Composite apis don’t have this, they’re just variables, they’re more flexible
Watch, computed
// vue2
watch: {
tableData (val) {
this.tableData2 = []
}
},
computed: {
price () {
return this.price1 * 20}}Copy the code
// vue3
<script setup>
import { ref, reactive,watch,computed,watchEffect } from 'vue'
let price = ref(10)
let price1 = ref(20)
let state = reactive({
price1: 10.price2: 20.price3: 0
})
// Listen for the ref attribute
watch(price1, (newVal,oldVal) = > {
console.log(newVal,oldVal)
})
// Listen for multiple ref attributes
watch([price, price1], ([newPrice, newPrice1], [prevPrice, prevPrice1]) = > {
console.log(newPrice, newPrice1)
})
// Listen to reactive properties
watch(() = > state.price1, (newVal,oldVal) = > {
console.log(newVal,oldVal)
})
watch(() = > state, (newVal,oldVal) = > {
console.log(newVal,oldVal)
})
const price = computed(() = > price1 * 20)
const price2 = computed(() = > state.price2 * 20)
// watchEffect
// Official description: Run a function immediately when tracing its dependencies responsively and rerunce it when the dependency changes
watchEffect(() = > {
const {price1,price2} = state
state.price3 = price1 + price2
})
</srcipt>
Copy the code
- Watch can listen to one or more data sources
- Watch listens to the reactive property by passing in a callback function
- WatchEffect automatically collects dependencies, so no properties are specified, which means that it will automatically execute the function once the first time it collects dependencies
The life cycle
// vue2
<script>
beforeCreate(){}
create(){}
mounted(){}
destory(){}
updated(){}... </srcipt>Copy the code
// vue3
<script setup>
import { onMounted,onUpdated,onUnmounted } from 'vue'
onMounted(() = > {
console.log('onMounted')
})
onUpdated(() = > {
console.log('onUpdated')})consoleLog (created) </srcipt> Generates created and onMountedCopy the code
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeUnmount -> onBeforeUnmount
- unmounted -> onUnmounted
- errorCaptured -> onErrorCaptured
- renderTracked -> onRenderTracked
- renderTriggered -> onRenderTriggered
- Vue3 removes the create related hooks, and setup can be understood as create and beforeCreate
ref
// vue2
<template>
<panel class="size-wrapper" ref="panel">This is the home page</panel>
</template>
<script>
mounted(){
console.log(this.refs.panel)
}
</srcipt>
Copy the code
Vue3 single ref
<template>
<panel class="size-wrapper" ref="panel">This is the home page</panel>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import Panel from '@/components/Panel.vue'
// ref passes null for automatic binding
let panel = ref(null)
onMounted(() = > {
// Since it is ref, the.value value is required
const panelRef = panel.value
console.log(panelRef)
})
</srcipt>
Copy the code
// vue3 multiple refs
<template>
<panel1 class="size-wrapper" :ref="el => setRefs(el, 'panel1')">This is the home page</panel1>
<panel2 class="size-wrapper" :ref="el => setRefs(el, 'panel2')">This is the home page</panel2>
<panel3 class="size-wrapper" :ref="el => setRefs(el, 'panel3')">This is the home page</panel3>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import Panel from '@/components/Panel.vue'
import Pane2 from '@/components/Pane2.vue'
import Pane3 from '@/components/Pane3.vue'
// React returns the call function
let refs = ref({})
let setRefs = (el, name) = > (refs.value[name] = el)
onMounted(() = > {
// Since it is ref, the.value value is required
const panel1Ref = refs.value.panel1
const panel2Ref = refs.value.panel2
const panel3Ref = refs.value.panel3
console.log(panel1Ref,panel2Ref,panel3Ref)
})
</srcipt>
Copy the code
- If ref=”form” is specified in the component, it must be collected in the script. In this version, if ref=”form” is specified and there is no ref to receive in the script, the vUE will automatically collect the form is undefined
- If ref needs to get a method from a subcomponent, the subcomponent needs to expose the related method, otherwise it cannot get it
component
/ / the parent component
<template>
<panel class="size-wrapper" ref="panel">This is the home page<DescDialog
v-model:visible="state.visible"
:data="state.data">
</DescDialog>
</panel>
</template>
<script setup>
import { reactive, onMounted } from 'vue'
import Panel from '@/components/Panel.vue'
let state = reactive({
visible: false.data: []
})
</srcipt>
Copy the code
/ / child component
<template>
<div>
<el-dialog title="Describe the details" v-model="visible" :show-close="false">
<div v-html="sizeData"></div>
<template #footer class="dialog-footer">
<el-button type="primary" @click="onConfirmClick()">Know the</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { defineProps, defineEmit, reactive, useContext } from 'vue'
// The method used to expose the component makes the component clearer to some extent
const { expose } = useContext()
defineProps({
visible: {
type: Boolean.default: () = > false
},
data: {
type: Array.default: () = >[]}})const emit = defineEmit(['update:visible'])
const onConfirmClick = () = > {
emit('update:visible'.false)
}
expose({
onConfirmClick
})
</script>
<style lang="less">
</style>
Copy the code
- Vue2: load. sync => V-modle :visbile
- Vue2 props => defineProps
- $emit => defineEmit for vue2,emit needs to specify a declaration
vuex
- The declaration import phase is the same as vue2. It is used in the same way as vue2. For example, declare user.js in modules.
import * as userApi from '@/server/api/user'
export default {
state: {
userInfo: {}},mutations: {
setUserInfo(state, data) {
state.userInfo = data
},
clearUserInfo(state, data) {
state.userInfo = {}
},
},
actions: {
async getUserInfo({ commit, state }) {
const res = await userApi.getUserInfo()
commit('setUserInfo', res.data)
}
}
}
Copy the code
- Component acquisition phase
<script setup>
import { isRef } from 'vue'
import { useStore,computed,isRef } from 'vuex'
const store = useStore()
const userInfo = computed(() = > store.state.user.userInfo)
const getUserInfo = () = > store.dispatch('getUserInfo')
const setUserInfo = () = > store.commit('setUserInfo')
const is = isRef(userInfo)
console.log(is)
// Print true, note that. Value is required if this attribute is used in script, and is ignored when used in templates
</script>
Copy the code
- UserStore Obtains vuEX information
routing
// vue2
<script>
mounted(){
console.log(this.$route.query)
console.log(this.$route.params)
// this.$router.push({path: /index})
}
</script>
Copy the code
// vue3
<script setup>
import { onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
onMounted(() = > {
console.log(route.query)
console.log(route.params)
// router.push({path: /index})
})
</script>
Copy the code
- The Router hasn’t changed much, it’s pretty much the same as vuex
Component instance
- Many times things like third-party UI frameworks or self-encapsulated AXIos requests are injected into the global root instance and then directly available to all components
// vue2
import Vue from 'vue'
Vue.prototype.$message = message
Vue.prototype.$notification = notification
Vue.prototype.$info = Modal.info
Vue.prototype.$success = Modal.success
Vue.prototype.$error = Modal.error
Vue.prototype.$warning = Modal.warning
/ / use
<template>
<panel class="size-wrapper" ref="panel">This is the home page</panel>
</template>
<script>
mounted(){
this.$loading().show()
this.$loading().close()
}
</srcipt>
Copy the code
// vue3
import App from '@/App.vue'
const app = createApp(App)
app.config.globalProperties.$message = message
app.config.globalProperties.$notification = notification
app.config.globalProperties.$info = Modal.info
app.config.globalProperties.$success = Modal.success
app.config.globalProperties.$error = Modal.error
app.config.globalProperties.$warning = Modal.warning
/ / use
<script setup>
import { getCurrentInstance } from 'vue'
// const { ctx } = getCurrentInstance()
// Use proxy instead of CTX
const { proxy: ctx } = getCurrentInstance()
onMounted(() = > {
const loading = ctx.$loading()
loading.closed()
})
</script>
Copy the code
- Get the current component instance with getCurrentInstance
- Note: The CTX attribute is valid only in the development phase. In the production environment, the CTX attribute will be GG directly. It is recommended not to use CTX, but to use proxy instead of CTX.
- If you look at the CTX source code, the result is an _.
Finally, the simplest configuration of vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()], / / the plugin
outDir: 'dist', // Package directory
// Server configuration
server: {
port: 3000,
open: true,
https: false,
ssr: false.// Set the proxy
proxy: {
'/api': {
target: 'http:/ / 127.0.0.1:8461 / API ',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
},
// @override command path
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
})
Copy the code
- vite
conclusion
- Vue3 feels like less code to write with the new syntax
- Composite apis are more flexible to develop and have better logic reuse
- The new DevTools doesn’t seem to be perfect, it’s just so-so to use, and sometimes data refreshes aren’t particularly real-time
- The development phase error sometimes doesn’t seem very specific
- Do not deploy with the getCurrentInstance().ctx property; it only takes effect during development
- Vue3 document reference