Vue3 knowledge
1. Vue.config. js configuration
Create a vue. Config. Js
Vue. Config. js is an optional configuration file that is automatically loaded by @vue/cli-service if it exists in the root directory of the project (the same as package.json).
This file should export an object containing options:
// vue.config.js
module.exports = {
/ / options...
}
Copy the code
Configuration options
publicPath
- Type:
string
- Default:
'/'
This value can also be set to an empty string (”) or a relative path (‘./’), so that all resources are linked to a relative path, so that the output package can be deployed in any path.
// The webpack configuration is merged with the public webpack.config.js
module.exports = {
// Run the NPM run build unified configuration file path ('./' is required for local access to dist/index.html)
publicPath: '/',}Copy the code
outputDir
-
Type:
string
-
Default:
'dist'
Directory of the production environment build file generated when vue-cli-service build is run. Note that the target directory is cleared before building (passing –no-clean at build time turns this behavior off).
outputDir:'dist'.// Package file output directory, by default package to dist file
Copy the code
assetsDir
-
Type:
string
-
Default:
''
The directory (relative to outputDir) where generated static resources (JS, CSS, IMG, fonts) are placed.
assetsDir:'static'.// Place static resources
Copy the code
pages
-
Type:
Object
-
Default:
undefined
Build the application in multi-Page mode. Each “page” should have a corresponding JavaScript entry file. The value should be an object whose key is the name of the entry and whose value is:
- One specified
entry
.template
.filename
.title
和chunks
Object (exceptentry
Everything else is optional); - Or one that specifies it
entry
String of.
- One specified
module.exports = {
pages: {index: {// Page entry
entry: 'src/main.js'.// Template source
template: 'public/index.html'.// Change the template engine title
title:"Vue3 learning".// Output in dist/index.html
filename: 'index.html',}}}Copy the code
lintOnSave
-
Type:
boolean
|'warning'
|'default'
|'error'
-
Default:
'default'
-
Check whether eslint-loader is used when saving. Valid values: true | | false “error” when set to “error”, check out the mistake will trigger compilation fails.
lintOnSave: false.// Sets whether esLint validation is enabled every time code is saved in the development environment
Copy the code
chainWebpack
-
Type:
Function
Is a function that takes a Webpack-chain-based ChainableConfig instance. Allows for more fine-grained changes to the internal WebPack configuration.
More details can be found at webpack > Chain operation
chainWebpack:config= > { // Allows more fine-grained changes to the internal WebPack configuration.
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options= > Object.assign(options, { limit: 10240}})),Copy the code
devServer
-
Type:
Object
All webpack-dev-server options are supported. Note:
- Some values like
host
,port
和https
May be overridden by command line arguments. - Some values like
publicPath
和historyApiFallback
Should not be modified as they are required and the development serverpublicPathSynchronization to ensure normal operation.
- Some values like
devServer:{
host: 'localhost'.port: 8090./ / the port number
hotOnly: false./ / hot update
https: false.// HTTPS :{type:Boolean} Configure the prefix
open: false.// Configure automatic browser startup
proxy: {
'/api': {
target: 'url'.// Whether cross-domain is allowed
changeOrigin: true.secure: false.// If the interface is HTTPS, you need to set this parameter
ws: true.// If you want to proxy WebSockets, configure this parameter
pathRewrite: {
'^/api': ' '}}}}Copy the code
Complete configuration
module.exports = {
/ / options...
publicPath: process.env.NODE_ENV === 'production'? ' ': '/'.// Usually used to determine whether the environment is in development or production
outputDir:'dist'.// Package file output directory, by default package to dist file
assetsDir:'static'.// Place static resources
pages: {index: {// Page entry
entry: 'src/main.js'.// Template source
template: 'public/index.html'.// Change the template engine title
title:"Vue3 learning".// Output in dist/index.html
filename: 'index.html',}},lintOnSave: false.// Sets whether esLint validation is enabled every time code is saved in the development environment
runtimeCompiler:false.// Whether to use a full build with an in-browser compiler
configureWebpack: { // Alias configuration
resolve: {
alias: {
'src': The '@'.// It is configured by default
'assets': '@/assets'.'common': '@/common'.'components': '@/components'.'api': '@/api'.'views': '@/views'.'plugins': '@/plugins'.'utils': '@/utils',}}},// Package CSS path and name
css: {
modules: false.// change CSS in vue file does not take effect
extract: {
filename: "style/[name].[hash:8].css".chunkFilename: "style/[name].[hash:8].css"}},chainWebpack:config= > { // Allows more fine-grained changes to the internal WebPack configuration.
config.module
.rule('images')
.use('url-loader')
.loader('url-loader')
.tap(options= > Object.assign(options, { limit: 10240}})),devServer: {host: 'localhost'.port: 8090./ / the port number
hotOnly: false./ / hot update
https: false.// HTTPS :{type:Boolean} Configure the prefix
open: false.// Configure automatic browser startup
proxy: {
'/api': {
target: 'url'.// Whether cross-domain is allowed
changeOrigin: true.secure: false.// If the interface is HTTPS, you need to set this parameter
ws: true.// If you want to proxy WebSockets, configure this parameter
pathRewrite: {
'^/api': ' '
}
}
}
}
}
Copy the code
2. Vue3 core syntax
For the Composition API, there’s an animated demo by the big guy, highly recommended.
The busy night Vue3 animation was good, but too short
Drawback of Option – repeated hop
// options API
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: {
type: String.required: true
}
},
data () {
return {
repositories: []./ / 1
filters: {... },/ / 3
searchQuery: ' ' / / 2}},computed: {
filteredRepositories () { ... }, / / 3
repositoriesMatchingSearchQuery () { ... }, / / 2
},
watch: {
user: 'getUserRepositories' / / 1
},
methods: {
getUserRepositories () {
// Use 'this.user' to get the user repository
}, / / 1
updateFilters () { ... }, / / 3
},
mounted () {
this.getUserRepositories() / / 1}}Copy the code
This fragmentation makes it difficult to understand and maintain complex components. The separation of options masks a potential logical problem. In addition, when dealing with a single logical concern, we must constantly “jump back and forth” to the option blocks of the related code.
When the requirements are complicated, watch, computed, inject, provide and other configurations are added, and the.vue file grows.
Composition API
-
Composition is to solve this problem. By means of combination, the codes scattered in various data and methods are recombined, and the codes of a function are maintained together, and these codes can be separately divided into functions
-
Vue3 is compatible with most of the SYNTAX of Vue2, so there is no problem writing Vue2 syntax in Vue3 (except for those that are deprecated).
setup
As an entry point to a composite API. Everything that setup returns is exposed to the rest of the component (computed properties, methods, lifecycle hooks, and so on) as well as to the component’s template.
Setup is executed only once on initialization, just like created().
beforeCreate(){
console.log('beforeCreate')},created() {
console.log('created')},setup(props) {
console.log('setup')}// setup
// beforeCreate
// created
Copy the code
According to the console print step, you can see that setup is executed before the beforeCreate life cycle. Setup calls occur before data Property, computed Property, or methods are resolved, so they cannot be retrieved in SETUP. Setup of execution time can be deduced from this, the component object has not been created, and is not available for this component instance objects, at the moment this is undefined, cannot access to the data/computed by this/the methods/props.
The use of the setup
// html
<button @click="handelClick">{{name}}</button>
// js
import { defineComponent, reactive, toRefs, onMounted } from 'vue'
setup(props) {
const state = reactive({
name:'click'
})
const handelClick =() = > {
console.log('handelClick')}// Anything returned here can be used for the rest of the component
return {
...toRefs(state),
handelClick
}
}
Copy the code
Ref response variable
In Vue 3.0, we can make any reactive variable work anywhere with a new ref function, as follows:
import { ref } from 'vue'
const counter = ref(0)
Copy the code
Ref takes the parameter and returns it wrapped in an object with a value property, which can then be used to access or change the value of a reactive variable:
import { ref } from 'vue'
const count = ref(0)
const handelClick =() = > {
// The format of XXX. Value is required. Value is not required in the template
console.log(count.value)
}
Copy the code
For example, a click on the event triggers a count increment
<template>
<div>{{count}}</div>
<button @click='handelClick'>Click on the</button>
</template>
Copy the code
In vue2
data() {
return {
conunt: 0}; },methods: {
handelClick() {
// The format of XXX. Value is required. Value is not required in the template
this.conunt++; }},Copy the code
In vue3
import { ref } from 'vue'
setup() {
const count = ref(0)
const handelClick =() = > {
count.value++
}
return {
count,
handelClick
}
}
Copy the code
reactive
const obj = reactive(obj)
Copy the code
Reactive transformation is “deep” — it affects all nested properties. In an ES2015 Proxy-based implementation, the returned Proxy is not equal to the original object. You are advised to use only reactive proxies to avoid relying on raw objects. Handles more complex data, typically for objects and arrays
A mock Ajax request returns an array
// html
<banner :bannerList="bannerList"></banner>
// js
import { defineComponent, reactive, toRefs, ref } from 'vue'
import api from '@/api/api.js'
setup() {
const state = reactive({
bannerList: []./ / round figure
})
const getBanners = async() = > {const {code,data} = await api.queryBannersByPosition({position:1})
if(code == 1) {
state.bannerList = data;
}
}
getBanners();
return {
...toRefs(state),
}
}
Copy the code
toRefs
Convert a reactive object to a normal object, where each property of the resulting object is a ref ‘that points to the corresponding property of the original object
function useFeatureX() {
const state = reactive({
foo: 1.bar: 2
})
// Operate on the logic of state
// Convert to ref on return
return {
// Deconstructed properties of objects returned through toRefs are also reactive. toRefs(state) } }export default {
setup() {
// Can be destructed without losing responsiveness
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
}
Copy the code
Computed properties
As with computed configuration in Vue2, an object of type REF is returned, and a get operation is passed in a function that evaluates an attribute
// html
<div>{{user}}</div>
// js
import { defineComponent, reactive, computed } from 'vue'
// Compute attributes computed
setup() {
const objname = reactive({name:'My object'})
const user = computed(() = > {
return objname.name + 'who'
})
return {
user
}
}
Copy the code
By default, you only have getters for computed properties, but you can also provide a setter if needed:
const user2 = computed({
get() {
return objname2.name+ '_'+ objname2.age
},
set(val) {
const age = val.split("_")
objname2.name = objname2.name + age[1]}})Copy the code
Watch the listener
As used with vue2, it is also lazy by default, meaning that callbacks are executed only when the source being listened on changes.
- Parameter 1: Data source to listen on
- Parameter 2: callback function
- Parameter 3: Configuration
Listening to a single data source
The listener data source can be a getter function that returns a value, or it can be directly ref:
// Listen for a getter
const state = reactive({
bannerList: []./ / round figure
name:Click '2'.count: 0
})
const handelClick2 =() = > {
state.count++
}
watch(
() = > state.count,
(count, prevCount) = > {
console.log('I'm being listened to.',count, prevCount); //logs: 1, 0})return {
...toRefs(state),
handelClick2
}
// listen on ref directly
const count = ref(0)
watch(count, (count, prevCount) = > {
console.log('I'm being listened to.',count, prevCount); //logs: 1, 0
})
Copy the code
Listening to multiple data sources
Watch listens for multiple data, using arrays
const firstName = ref(' ');
const lastName = ref(' ');
watch([firstName, lastName], (newValues, prevValues) = > {
console.log(newValues, prevValues);
})
firstName.value = "John"; // logs: ["John",""] ["", ""]
lastName.value = "Smith"; // logs: ["John", "Smith"] ["John", ""]
Copy the code
Listen for reactive objects
Use listeners to compare the values of an array or object that are reactive and require it to have a copy of the values.
const numbers = reactive([1.2.3.4])
watch(
() = > [...numbers],
(numbers, prevNumbers) = > {
console.log(numbers, prevNumbers);
})
numbers.push(5) / / logs: [1, 2, 3, 4, 5] [1, 2, 3, 4]
Copy the code
watchEffect
To automatically apply and reapply side effects based on reactive state, we can use the watchEffect method. It executes a function passed in immediately, tracing its dependencies responsively, and rerunking the function when its dependencies change.
Contrast:
Watch is executed only when the value listens for changes. You can set immediate to true to specify that the first time is executed immediately.
WatchEffect can be executed immediately for the first time.
const count = ref(0)
watchEffect(() = > {
console.log('I'm being listened to.',count.value); // logs: I am monitored 0
})
Copy the code
Stop listening
When watchEffect is called on a component’s setup() function or lifecycle hook, the listener is linked to the component’s lifecycle and stops automatically when the component is uninstalled.
In some cases, it is also possible to explicitly call the return value to stop listening:
const stop = watchEffect(() = > {
/ *... * /
})
// later
stop()
Copy the code
Lifecycle hook
You can access a component’s lifecycle hook by prefixing it with “on”.
The following table contains how to invoke lifecycle hooks within setup () :
Option type API | Hook inside setup |
---|---|
beforeCreate |
Not needed* |
created |
Not needed* |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
activated |
onActivated |
deactivated |
onDeactivated |
TIP
Because setup runs around beforeCreate and Created lifecycle hooks, there is no need to explicitly define them. In other words, any code written in these hooks should be written directly in the Setup function.
New life cycle
setup(props,context) {
onBeforeMount(() = > {
console.log('onBeforeMount')
})
onMounted(() = > {
console.log('onMounted')
})
onBeforeUpdate(() = > {
console.log('onBeforeUpdate');
})
// Render when the view is updated
onUpdated(() = > {
console.log('onUpdated');
})
onUnmounted(() = > {
console.log('onUnmounted')})// First render execution
onRenderTracked(() = > {
console.log('onRenderTracked')})// Re-render the page
onRenderTriggered(() = > {
console.log('onRenderTriggered')})const name = ref('Joe')
const handelClick = () = > {
name.value = 'wujf'
}
return {
name,
handelClick
}
Copy the code
Dojo.provide and inject
We can also use provide/inject in the composite API. Both can only be called during setup() of the current active instance.
Function: Enables communication between components across hierarchies
The provide function allows you to define a property with two arguments:
- name (
<String>
Type) - value
provide(name,value)
Copy the code
/ / the parent component
<template>
<div>
<My-Map></My-Map>
</div>
</template>
<script>
import { defineComponent, reactive, toRefs, ref, computed, watch,watchEffect, provide } from 'vue'
import MyMap from '@/components/my-map/my-map.vue'
export default defineComponent({
components:{
MyMap
},
// Provide and inject
setup() {
const msg = ref('Child components pass information')
const state = reactive({
obj: {name: 'Net reconciliation'.age: 19
}
})
provide('msg',msg)
provide('obj',state.obj)
}
})
</script>
Copy the code
The Inject function takes two parameters:
- The name of the property to inject
- Default value (Optional)
inject(name)
Copy the code
<template> <! My-map.vue --><div>
{{msgF}}
<div>Name: {{obj.name}} / age: {{obj.age}}</div>
</div>
</template>
<script>
import { defineComponent, inject } from 'vue'
export default defineComponent({
// Use of inject
setup() {
const msgF = inject('msg')
const obj = inject('obj')
return {
msgF,
obj
}
}
})
</script>
Copy the code
Posterity component
/ / the parent component
provide('my-map-son',state.obj) <template> <! My-map-son.vue --><div>
<div>Name: {{obj.name}} / age: {{obj.age}}</div>
</div>
</template>
<script>
import { defineComponent, inject } from 'vue'
export default defineComponent({
// Provide and inject
setup() {
const obj = inject('my-map-son')
return {
obj
}
}
})
</script>
Copy the code
Use of the setup parameter
When you use the setup function, it takes two arguments:
props
context
Props: is an object that holds the data passed by the parent component to the child component and all properties received by the child component using props
<! -- Parent component --><template>
<div>
<My-Map :list="list"></My-Map>
</div>
</template>
<script>
import { defineComponent } from 'vue'
import MyMap from '@/components/my-map/my-map.vue'
export default defineComponent({
components:{
MyMap
},
// Provide and inject
setup() {
const list = [1.2.3.4]
return {
list
}
}
})
</script>
/ / child component
<template>
<! My-map.vue -->
<div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
props: {list: {type: Array.default: () = >[]}},components:{
MyMapSon
},
setup(props) {
console.log(props.list) // [1, 2, 3, 4]}})</script>
Copy the code
One note: Because props are reactive, you can’t use ES6 deconstruction, which eliminates the responsiveness of prop.
If you need to deconstruct a prop, you can do this using the toRefs function in the setup function:
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
Copy the code
Context: The second argument passed to the setup function is Context. Context is a plain JavaScript object that exposes the component’s three properties:
export default {
setup(props, context) {
// Attribute (non-responsive object), which gets all objects on the current component tag that do not have properties received by props, equivalent to this.$attrs
console.log(context.attrs)
// slots (non-responsive object), the object that contains all the incoming slot content, equivalent to this.$slots
console.log(context.slots)
// Emit events (methods), a function that distributes custom events, equivalent to this.$emit
console.log(context.emit)
}
}
Copy the code
Context is a normal JavaScript object, that is, it is not reactive, which means you can safely use ES6 deconstruction of the context.
// MyBook.vue
export default {
setup(props, { attrs, slots, emit }){... }}Copy the code
Attrs Use: Gets the child component’s custom data
/ / the parent component
<template>
<div>
<my-son msg="Made you call me daddy."></my-son>
</div>
</template>
/ / child component
<template>
<div>Child components</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
setup(props,{attrs, slots, emit}) {
console.log(attrs.msg) // Call you daddy}})</script>
Copy the code
Slots using
/ / the parent component
<template>
<div>
<my-son msg="Made you call me daddy.">Gets the contents of the slot</my-son>
</div>
</template>
/ / child component
<template>
<div>Child components</div>
</template>
<script>
import { defineComponent,h } from 'vue'
export default defineComponent({
setup(props,{attrs, slots, emit}) {
console.log(attrs.msg) // Call you daddy
console.log(slots.default()) //
return () = > h('div',{},slots.default()) // Outputs the contents of the custom component slot}})</script>
Copy the code
Output the contents of the custom component slot:
Emit use: sends events to the parent component
/ / the parent component
<my-son @change="handelChange">
</my-son>
setup() {
const handelChange =() = > {
console.log('23456')}return {
handelChange,
}
},
/ / child component
<template>
<div>
<button @click="handelClick">Child components</button>
</div>
</template>
<script>
import { defineComponent,h } from 'vue'
export default defineComponent({
setup(props,{attrs, slots, emit}) {
const handelClick =() = > {
emit('change')}return {
handelClick
}
},
})
</script>
Copy the code
Teleport portal
You can optionally mount it to the specified DOM node
Grammar:
// To specify node positions such as. Box, #warp<teleport to="body">
// html
</teleport>
Copy the code
For example: cover the entire body with a shadow layer
<template>
<div>
<div class="box">
<button @click='clickBtn'>Click on the</button>// to specifies the location of the element to hang<teleport to="body">
<div v-show="show" class="mask">
</div>
</teleport>
</div>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const show = ref(false)
const clickBtn =() = >{ show.value = ! show.value }return {
clickBtn,
show
}
},
})
</script>
<style>
.box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
background-color: aqua;
z-index: 10;
}
.mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: # 000;
opacity:.5;
}
</style>
Copy the code
Effect:
Initial position:
<div v-show="show" class="mask">
</div>
Copy the code
With Teleport, the mask shadow layer is already hanging under the body.
<teleport to="body">
<div v-show="show" class="mask">
</div>
</teleport>
Copy the code