1. Vscode extends Volar
The editor tool I use is vscode, and vue3’s vscode extension is called volar, and volar and vetur do not coexist.
1.1. Install Volar
Type volar in the extensions store and it will come up with three extensions. My advice is to install them all. If you don’t use TS then the TypeScript Vue Plugin (Volar) doesn’t need to be installed.
1.2, configuration,
The Vue Volar Extention Pack extension has 12 dependency extensions that are not installed and ready to use
Open Settings (File -> Options -> Settings) and then we need to customize the following extensions
The most important configuration items are:
1.2.1. Automatic Formatting.vue
file
If this option is not checked, your.vue will not be automatically formatted!!
1.2.2 disable built-in TS support for vscode
In the extension store we type: @builtin typescript, then find typescript and JavaScript Language Features and disable it, as shown here:
Volar has built-in TS support, which means that vscode has two TS processes. This is not necessary. The most direct expression is that two TS processes will appear as follows:
After we install volar, every time we open vscode, there will be the following prompt box in the lower right corner, click to view the original text.
2, the import. Meta. Env
Environment variables and modes TS module enhancements
In Vite we can use import.meta.env. XXX directly to use the data we defined in the.env file.
If we need precise type hints for custom data in TS, the official way is to use the TS module enhancement in the env.d.ts file.
But it has the following two pits.
2.1. Declaration inenv.d.ts
The invalid
In this case, MY solution is to create another arbitrarily named.d.ts file and place the ImportMetaEnv definition in it.
In 2.2,vite.confing.ts
Cannot be used inimport.meta.env.xxx
Ts does not support import.meta. Env. There are many related articles on the Internet.
Yarn add dotenv -d yarn add dotenv -d
3. Some component styles are missing when ElementPlus is imported on demand
There are a lot of element-Plus components, but we only use some of them. We can manually import the components that we need, but this will increase the maintenance cost. The official also provides an automatic import solution.
According to the official document, I configured the project with automatic import on demand. When I used ElMessage or ElMessageBox, I found that the function was ok, but it had no style……
The original idea was to import element-Plus globally, but the styles are already there, but some components have two styles, which is a complete departure from the original intent of importing on demand or even importing all the components at once.
Then I went to the source code of the automatic import component unplugin-vue-components to see its import rules
According to the style introduction rule of unplugin-vue-components, we go to the node_modules/element-plus/theme-chalk/ directory of the project to find the corresponding component style and import it manually.
The problem was fixed, but it didn’t feel elegant enough, and at one point IT occurred to me that when I was reading the Elemental-Plus documentation it seemed to have a plugin, so I went there and found it in a corner!
Install and configure it according to its GitHub documentation, and you’re done. My understanding of unplugin-element-plus is that it is a complement to, not a substitute for, unplugin-vue-components. Don’t ask me why I use this phrase (T, T).
4, <script lang=”ts” setup>
In
<script lang="ts" setup>
const props = defineProps({
name: String.color: String,
})
</script>
Copy the code
But when we encounter complex data types, we can get confused
<script lang="ts" setup>
interface Account {
name: string
age: number
sex: 'male' | 'woman'
}
const props = defineProps({
account: Account // Not supported. The value here only supports data types that exist in JavaScript
})
</script>
Copy the code
<script lang="ts" setup>
interface Account {
name: string
age: number
sex: 'male' | 'woman'
}
const props = defineProps<{ account: Account }>()
</script>
Copy the code
This generic writing is not surprising, even the parameters do not need to pass!
5, defineComponent
5.1. Props statement
When we customize components, we usually use defineComponent for better syntax hints, as follows:
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Demo'.setup(props) {},
})
</script>
Copy the code
But I’m also having props declare problems on defineComponent, which is probably the newbie’s sad o ﹏ o.
In the defineComponent configuration item setup function, its first argument is the specific value of props and is reactive. So we can’t deconstruct it directly, only using toRef or toRefs.
<script lang="ts">
import { defineComponent, ref, toRef, toRefs } from 'vue'
export default defineComponent({
name: 'Demo'.// Setup ({name, color}) {}, // Error writing, this will make the props unresponsive
setup(props) {
const name = toRef(props, 'name')
/ / or
const { name, color } = toRefs(props)
},
})
</script>
Copy the code
This is a minor detail that you can’t make if you read the document carefully. So let’s get to the point. Why did props fail?
My initial thought was that defineComponent supported generic writing as well as defineProps, so I went to the.d.ts file of vue and saw that it did
At this point, you’ll be too happy. Although the syntax hints for TS are already there, you’ll find console.log({… Props. Account}) is an empty object with no data…….
Then I looked at the source code for element-Plus to see how they wanted to write props
That’s right, enforce its TS type with type assertion using AS.
5.2, DOM ref
In vue2, we usually use this.$refs. XXX to call a registered component or native DOM that registers a ref attribute. However, vue3’s setup function is a bit tricky to get a component or DOM that registers ref attributes, especially in TS environments.
5.2.1 Basic usage of DOM Ref
What is marked in the image is important, and these details are not marked in the official documentation. One of the most confusing areas for beginners is the definition. Ref (null) is used exactly the same as a reactive API ref, which makes it easy to get confused.
The template references the reactive API ref
5.2.2 TS type of DOM Ref
In TS, the type of ref(null) is automatically inferred to be ref
, which is very bad for our subsequent coding, such as:
The only way to get around this problem is to use as for type assertions, as long as our syntax meets the three basic requirements of DOM Ref.
5.2.3 requires,ElForm.validate
的 TS
type
When we use element-Plus forms, we generally validate the form data before submission. With previous experience you might write code like this:
“Validate” and “valid” TS are both of type any. So now we need to cheat again, and what I do is I create a custom ElFormInst type declaration that takes all the methods and attributes that I need out of it. Then replace the Typeof ElForm.
6. Unlimited menu bar
I mention this because it involves recursive references to components, and official recursive component descriptions are rare.
Although the official said that support, but I did not succeed, either TS check but not render recursion effect, difficult to top!! You can teach me if you have achieved it
Although it was not possible to implement the infinite level menu bar through recursive components, it was eventually implemented in pure TS code by looking through the VUE documentation and the Element-Plus documentation
/** * infinite level side navigation bar */
import UIconfont from '@@/UIconfont.vue'
import { ElMenu, ElMenuItem, ElSubMenu } from 'element-plus'
import { defineComponent, h, VNode } from 'vue'
import { useRouter } from 'vue-router'
interface MenuItem {
icon: string
title: string
router: stringchildren? : MenuItem[] }export default defineComponent({
name: 'Menus'.setup() {
const router = useRouter()
function select(index: string) {
router.push(index)
}
return { select }
},
render() {
function common(menu: VuexSidebarItem) : () = >VNode[] {
return () = > [
h(UIconfont, { name: menu.icon, class: 'menu-icon' }),
h('span'.null, menu.title)
]
}
function create(menu: VuexSidebarItem) :VNode {
if (menu.children) {
return h(
ElSubMenu,
{ index: menu.router }, // index prop
{
title: common(menu), // title slot
default: () = >menu.children! .map(create)// default slot or childrens})}return h(ElMenuItem, { index: menu.router }, common(menu))
}
const defaultOpeneds: string[] = this.$store.getters.assideOpends
return h(
ElMenu,
{
defaultOpeneds, // default-openeds prop
onSelect: this.select, // @select
style: 'border: none'.// style attribute
},
// store.state.aside: MenuItem[]
() = > this.$store.state.aside.map(create) // default slot or childrens)}})Copy the code
For more information, see the element-Plus source code.
7. Axios encapsulation
By default, axios returns this data when the request succeeds
interface AxiosResponse<T = any, D = any> {
data: T
status: number
statusText: string
headers: AxiosResponseHeaders
config: AxiosRequestConfig<D> request? :any
}
Copy the code
This is how it will be used
interface ResponseData<T> {
code: string
data: T
msg: string
}
axios.get<ResponseData<string[] > > ('xxx/xxx').then((response) = > {
const { code, data, msg } = response.data
if (parseInt(code) ! = =1) {
return alert(msg)
}
console.log(data)
})
Copy the code
We typically use axios’s response interceptor to process the response data, and your data structure might look something like this
interface AxiosResponse<T = any, D = any> {
code: number
data: T
message: string
status: number
statusText: string
headers: AxiosResponseHeaders
config: AxiosRequestConfig<D> request? :any
}
Copy the code
The way it’s going to be used is going to be
interface ResponseData {
pageTotal: number
pageSize: number
pageNum: number
content: string[]
}
axios.get<ResponseData>('xxx/xxx').then((response) = > {
const { pageTotal, content } = response.data
})
Copy the code
If you use JS, you can encapsulate it directly, but if you use TS, you will find that the validation fails
In this case, we can use the previously mentioned TS module enhancement to handle this. It is worth noting that this time we can put the declaration in the env.d.ts file as follows:
import { AxiosInstance } from 'axios'
declare module 'axios' {
interface AxiosResponse {
code: number
message: string}}Copy the code
Final preview
7, at the end
Novice novice use, hope you big guy correct the wrong place (‘ ω · ´)