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 specifiedentry.template.filename.titlechunksObject (exceptentryEverything else is optional);
    • Or one that specifies itentryString of.
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 likehost,porthttpsMay be overridden by command line arguments.
    • Some values likepublicPathhistoryApiFallbackShould not be modified as they are required and the development serverpublicPathSynchronization to ensure normal operation.
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:

  1. name (<String>Type)
  2. 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:

  1. The name of the property to inject
  2. 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:

  1. props
  2. 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