Customized, high-availability front-end style processing solution
Pain points in CSS processing under enterprise-level projects:
Unified variables are difficult to maintain
Lots of className overhead
The writing burden caused by the separation of HTML and CSS
Responsive, theme switching is complex to implement
For more pain points, see CSS Utility Classes and “Separation of Concerns”
In response to the above problems, we can solve it through tailwindcss. Let’s look at its specific usage below.
Installation
|
|
Initializes the tailwindcss.config.js
configuration file and also creates the postcss.config.js
file.
|
|
|
|
Add instructions to load Tailwind to your CSS file
|
|
Use built-in class names on elements
Tailwindcss is officially introduced to quickly build modern websites without leaving HTML. Specifically, tailwind provides many class names, all of which define specific css. You can quickly build a website by directly adding the corresponding class name when writing HTML.
The design concept of tailwindcss
First, let’s take a look at the css granular design form
- Inline styles. The highest degree of freedom and the strongest customization. But it is inconvenient to reuse styles.
|
|
- Atomized css, each class name represents a type of css style. The degree of freedom is still very strong, the customization is also very high, and the styles can be reused. But a lot of meaningless class names will be written. Among them, tailwindcss is this design.
|
|
- In the traditional form, one or several semantic classes are used to describe a CSS attribute. It is encapsulated, has strong semantics, and has average freedom and customizability (most class names are written with the entire set of CSS attributes of the corresponding element). However, there are a large number of semantic classes, which require switching back and forth between HTML and CSS when writing.
|
|
- In component form, the structure and style are directly defined in the current component. It has strong encapsulation and strong semantics. However, the degree of freedom and customizability are relatively poor. And the style is fixed, which is more suitable for background projects. Such as element-plus and so on.
|
|
- Comparing the four design methods, we can see that atomized CSS has a degree of freedom, is customizable, and has good reusability. It only has the disadvantage of writing a large number of meaningless class names. Compared with its advantages, the disadvantages can be ignored. But for those who maintain the project, if they don’t understand the class names defined in tailwindcss, it may be a very headache.
For high personalization, high interactivity, and highly customized front-end project style solutions, the atomized CSS form is more suitable.
When developing with vscode, we can install a Tailwind CSS IntelliSense plug-in to prompt for class names to help us develop better.
VueUse A practical toolset for Vue’s compositional API
VueUse, a set of practical tools based on Vue’s composite API. It encapsulates many common and reusable functions. It supports Vue2, Vue3, and Nuxt. It can be understood as the lodash of the Vue world. It can be used out of the box and is very convenient.
The core package has 140+ combined functions, and also provides 10 extension plug-ins, totaling about 290+ functions.
Function
State: Manage user status (such as: global, local storage, session storage)
Elements: Element processing related (such as: element dragging, element visibility, window size)
Browser: Browser related (such as: updating page title, media query, clipboard)
Sensors: monitor different DOM events, input events, network events, etc.
Network: Network request related
Animation: Transitions, timeouts and timing functions
Component: Provides abbreviations for different component methods
Watch: Provides some monitors (such as: monitoring changes after promises, anti-shake monitoring, throttling monitoring)
Reactivity: Responsive function related
Array: Responsive array processing
Time: Provides response time formatting function
Utilities: general functions, such as throttling, anti-shake, etc.
Plugin: Electron、Firebase、Head、Integrations、Math、Motion、Router、RxJS、SchemaOrg、Sound
The core functions are all in the packages/core folder.
Installation
|
|
Use
all it directly as a function: for example,
const { toggle } = useFullScreen()
, which is also our most commonly used method.Used as a component: Some functions are provided, such as
<UseFullscreen><UseFullscreen>
.
When called directly as a function, you can receive responsive parameters. Most functions will return a refs object, and you can use object destructuring to obtain the required content. Functions usually start with use.
For component usage, in addition to installing the @vueuse/core
core package, you also need to install @vueuse/components
, that is
|
|
VueUse encapsulates many practical functions, such as: clipboard (useClipboard), anti-shake (useDebounceFn), setting the title of the web page (useTitle), and listening for events (useEventListener). Page uninstallation can automatically help us delete event monitoring without us having to delete it manually. etc. Before encapsulating hooks yourself, you can go to the official website to see if they have been encapsulated to improve development efficiency.
VueUse also has good interactive documentation and function demonstrations. It is written in TS. The core source code of each function is relatively small and easy to read. In addition to using its encapsulated functions, we can also learn function encapsulation skills by looking at its source code. Learn good coding habits.
Why is vite faster than webpack?
When building during webpack development, your entire application will be crawled and built by default before it can provide services. This will cause any error in your project (even if the current error is not a module referenced on the homepage), it will still affect it. to your entire project build. So the bigger your project is, the longer the build time will be and the slower the project startup will be.
Vite will not build your entire project at the beginning, but will divide the modules in the reference into two parts: dependency and source code (project code). For the source code part, it will split the code modules according to routing, and will only go Build what you have to build from the get-go.
At the same time, Vite provides the source code to the browser in the form of native ESM, allowing the browser to take over part of the packaging work.
vite development configuration
Configure path alias
|
|
Development environment solves cross-domain issues
|
|
Configure environment variables
Enterprise-level projects will distinguish many environments for us to test and trial. We cannot let our test data contaminate the online data. Therefore, Vite also provides a way to configure our environment files, allowing us to easily select the corresponding interface address and so on through some environments.
The format of .env.[mode]
can load different content in different modules.
Environment loading priority:
A file that specifies a pattern (e.g.
.env.production
) will take precedence over a generic form (e.g..env
).In addition, environment variables that already exist when Vite is executed have the highest priority and will not be overwritten by the
.env
class file. For example when runningVITE_SOME_KEY=123
vite build ..env
The class file will be loaded when Vite starts, and changes will take effect after restarting the server.
We can obtain loaded environment variables starting with VITE_
through import.meta.env.*
in the code.
|
|
After executing yarn dev , we can find that import.meta.env.VITE_BASE_API is the parameter specified in the command line.
Automatic registration of common components
Vite’s Glob import function: This function can help us import multiple modules in the file system
|
|
Then introduce it through the way of registering asynchronous components provided by vue. Vue’s defineAsyncComponent
method: This method can create an asynchronous component that is loaded on demand. Based on the above two methods, the component can be automatically registered.
|
|
In fact, if the components all provide the name attribute, we can directly manually introduce each component module and then achieve semi-automatic registration.
The advantage of providing a name for a component is that it is convenient to find each component when debugging in vue-devtools.
In the vue official website, in versions 3.2.34 or above, the single-file component using <script setup>
will automatically generate the corresponding name option based on the file name, even when used with <KeepAlive>
There is no need to declare manually when using it. But for us developers whose file names are all index.vue, there is no way.
Use svg as icon
First we need to encapsulate a general svg component to use svg icons.
|
|
Then register the svg universal component globally. Here we use the plug-in method.
|
|
After registering directly through use in main.js, it can be used.
|
|
However, the path of the svg icon cannot be known in the project. We need to use the vite-plugin-svg-icons
plug-in to specify the search path.
Configure svg related content in vite.config.js
|
|
Import and register svg-icons in main.js, it will register all svg images in the specified folder on the homepage.
|
|
Persistent state data vuex-persistedstate
vuex-persistedstate, as a plug-in of vuex, can persist the data in the store to prevent data loss due to page refresh and other operations. (When running again, the cached data will be used as the initial value of the corresponding state attribute)
|
|
Theme switching implementation
Implementation idea: (This solution is based on the tailwindcss plug-in)
The tailwind.config.js
configuration file needs to be added
|
|
Store current theme type in vuex
|
|
Modify the theme type in vuex when switching themes
|
|
Monitor changes in theme types: theme-light, theme-dark, theme-system, and dynamically set the class attribute value for the html tag. He just adds the css prefix to the corresponding theme to the html element when switching. To achieve the effect of switching themes
|
|
After the value of the class attribute of html changes, it will match the class of the corresponding theme, thereby displaying the color of the corresponding theme.
Set two sets of class names for labels: one for white and one for dark.
|
|
To follow the theme changes of the system, you need to use Window.matchMedia()
. This method receives a mediaQueryString (a string parsed by the media query). We can pass the prefers-color-scheme to this string, that is, window.matchMedia('(prefers-color-scheme: dark)')
The method returns a MediaQueryList
object.
This object has a
change
event that can listen for system theme changes.The event object
matches
attribute can determine the theme. (true: dark theme, false: light theme).
Theme modification tool function
|
|
Implement waterfall flow layout
The construction of the entire waterfall flow component generally needs to be divided into several parts
- Pass key data through props
data: data source
nodeKey: unique identifier
column: number of columns rendered
columnSpacing: column spacing
rowSpacing: row spacing
picturePreReading: Whether picture pre-rendering is required
Waterfall rendering mechanism: layout is completed through absolute and relative. The layout logic is: each item should be arranged horizontally, and the items in the second row are sequentially connected to the current shortest column.
Pass the key data involved in each item to the item view through the scope slot.
Calculate the width of each column
The general calculation method is to get the container width (excluding margin, padding, border),
|
|
And get the total spacing of each item element in the container.
|
|
Then subtract the total spacing from the current container, divided by the number of columns.
|
|
Get the height of each element
Whether the height of the image is defined. If the height is defined, the height of each item can be calculated directly.
|
|
If the height is not defined, we need to calculate the height after the image is loaded.
Get item element
Get the image path in the itm element
|
|
- Use the load event of the image object to determine whether the image is loaded, and then calculate the height.
|
|
|
|
Calculate the offset of each element
They are all calculated based on obtaining the minimum height of the column.
You need to initialize the height of each column to 0, use this object as a container, the key is the column subscript, and the value is the column height.
|
|
When getting the left offset, we need to get the minimum height column.
|
|
After getting the minimum height column, just multiply it by the column width and add the spacing.
|
|
To calculate the top offset, we can directly get the minimum height column height.
|
|
It should be noted that when we complete each element offset assignment, we need to recalculate the height of the minimum height column.
|
|
Finally, assign the maximum height column height to the container height.
|
|