banner
isolcat

isolcat

I am not afraid of storms, for I am learning how to sail my ship
github

First Attempt at Vue 3.2+ with Typescript

Preface#

I saw Evan You saying " <img src="https://pic.rmb.bdstatic.com/bjh/b4eef54de9356cc73a57c98bf8b6f315.png" alt="image.png" style="zoom:80%;" />

Recently, I happened to come across a related project online, which aroused my curiosity again. I thought there was nothing else to do, so I tried it out this summer and encountered many problems when using the <script setup> syntax sugar and TypeScript. I also felt the joy of <script setup> + ts during the process of completing this project. I have to say, it's really comfortable, hahaha.

Without further ado, let's talk directly about the advantages I experienced and some problems I encountered during the development of the project.

Advantages:#

More concise code#

In Vue 3.2, the <script setup> syntax sugar is officially supported, which reduces a lot of repetitive template code. Imported components no longer need to be registered before they can be used. Once imported, they can be used directly in the SFC. Here's an example to demonstrate the effect:

<template>
    <Header />
</template>

<script setup>
// Imported components can be used directly without registration
import Header from './header.vue'
</script>

Not only the import of components does not require separate registration, but also the declaration of functions and variables greatly reduces the amount of code. With <script setup>, there is no need to return the value of variables, and for functions, there is no need to expose them through the methods option. Functions can be directly written in the setup block. Here's an example from the official documentation:

<script setup>
// Variables
const msg = 'Hello!'

// Functions
function log() {
  console.log(msg)
}
</script>

<template>
  <button @click="log">{{ msg }}</button>
</template>

More detailed project interfaces#

In this project, I used mock.js to write interfaces and made the interfaces work by importing '@/mock/index'. In actual projects, when I need to call an interface, I need to define the interface using TypeScript. Although this will increase the amount of code to some extent, it will be more convenient for maintenance in medium and large projects. There will also be code hints when calling interfaces, which is an advantage of TypeScript.

Here's an example:

<script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'

// Define the interface using TypeScript
interface Iswiper {
  imgSrc: string
  link: string
}
const list = ref<Iswiper[]>([])

axios({
  url: '/swiperList',
  method: 'get'
}).then((res) => {
  console.log(res.data.result)
  list.value = res.data.result
})
</script>

When we hover over it, we will see the prompt: image.png, which greatly facilitates the calling of interfaces and future maintenance. For a detailed tutorial on TypeScript, you can refer to this article to gain a deeper understanding of interface.

Problems encountered during project development#

Unable to navigate with the router#

The mistake I made here was actually because I didn't grasp <script setup> well enough. When I wanted to click the search button to navigate, an error occurred - no response no matter how I clicked. I wanted to use this.$router.push directly in <script setup> to navigate, but at this moment, setup has not been executed yet, and there is no Vue instance, let alone this.

Looking at the Vue Router official documentation, we can clearly see the explanation: image.png

Since the setup function is executed before the beforeCreate hook, data and methods cannot be used in the setup function (because they have not been initialized yet). In order to prevent us from using data and methods incorrectly, Vue directly modifies this in the setup function to undefined.

However, since the "search icon" in this project is an <a> tag, there is no need to use the useRouter function. We can directly add the navigation logic to the <a> tag:

image.png

Note that since we are using the default "hash" mode for routing, we should not add /search directly here, otherwise the page will not navigate. We should add a # before it.

Unable to modify component styles#

The inability to modify component styles has also been encountered in previous projects. The default styles of the "element plus" components cannot be modified, and the same problem was encountered in "vant3". Our own styles are overridden. In this case, we can directly use "style piercing" by using the ::deep syntax: ::deep .className { styles to modify }:

image.png

CSS modules#

When I was modifying the style of the login page, I encountered a problem. I couldn't change the background color of the entire page. I found that modifying the style of body didn't work. If I directly delete the scoped attribute in the <style> tag of the Vue single-file component, the style will take effect, but the side effect is that the style cannot be private and will pollute the global scope.

At this time, there are two solutions:

Open a separate style tag#

By opening another <style> tag, we can render the body separately.

Use global scope#

CSS Modules allows the use of :global(.className) syntax to declare a global rule. image.png

For more details about CSS Modules, you can refer to this article by Ruanyifeng: CSS Modules Usage Guide

defineExpose#

When using the "vant3" components, because its documentation instance does not use <script setup> directly like "element plus", I wrote it in this format: image.png

As a result, all the input boxes in my login page disappeared... I realized that it was probably because I didn't handle the <script setup> syntax sugar well. I quickly looked at the Vue official documentation and unsurprisingly found the reason for the problem: In fact, it is not possible to directly access the public instance of a component through ref in the <script setup> function. We need to use defineExpose.

Components using <script setup> are closed by default - that is, the public instance of the component obtained through template refs or $parent chain will not expose any bindings declared in <script setup>.

Use the defineExpose compiler macro to explicitly specify the properties to be exposed in <script setup> components.

image.png

Note that defineExpose needs to be manually imported.

Conclusion#

<script setup> + TS + Volar is really awesome. Although I still don't have a good grasp of the <script setup> syntax sugar, which led to a series of problems during the development process, I can still feel the charm of the syntax sugar. Finally, I will attach the project and source code links:

Source code: https://github.com/isolcat/vue3-ts-bilibili

Project preview: https://vue3-ts-bilibili.vercel.app

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.