The focus of my work in the last week is to sort out the team norms, and I have also checked and missed a lot of knowledge in the writing process. After removing the part about the company scene, I have this series of articles, which are expected to be written in four parts:
- Git specification
- Engineering specifications
- User experience specification
- Naming conventions
User experience specification
User experience is a huge topic and everyone’s understanding of experience is different. Along with timeliness, with the emergence of new technologies, the previous experience may become outdated quickly, so the following content can only be briefly summarized.
General guidelines
Increased clickable area size
For example, if you have to click to the Checkbox area to take effect, it will inevitably lead to poor experience
Component consistency also includes page structure, as shown in the figure above, label and checkbox as a whole. Here are some common elements that apply to this rule:
- The picture picture and name in the upper right corner of the header area;
- Label, Li and other integral row elements;
- Custom ICONS
- .
Try to avoid user click costs when interacting with the above elements. Here are two common practices
Click to enlarge the overall area, such as the following image area
<p class="portrait">
<img class="portrait-img" src="xxx" />
<span class="portrait-name">xxxx</span>
</p>
Copy the code
If the click event is bound to.portrait-img, consider adding it to.portrait
Increases the click area of the element itself
<i class="i-con"></i>
Copy the code
The I element above is usually used to set custom ICONS, but in practice, the user’s mouse or gesture may be biased so the element’s scope needs to be increased.
Returning to the CSS box concept, we can add a border to accomplish the effect of adding a region
.i-con {
/* omit other code */
border: 5px solid transparent;
}
Copy the code
Note: PC also needs to consider cursor consistency, as well as hover and a series of overall effects
Image correlation optimization
For many projects, pictures are a common optimization point, after all, multi-faceted optimization is far less intuitive than compression of a picture, but also for user experience
preload
Different from lazy loading, the purpose of preloading is to output images in advance so that users don’t have to wait.
To take a common example, pre-loading is a good idea for rote graphics, otherwise it would be awkward for the user to wait for the next image to load.
The principle of preloading is to request the same resource in advance, and then return the cache file when the same resource is requested repeatedly. We can encapsulate a method, using Image to assign a value to SRC
const preloading = (src) = > {
return new Promise((resolve, reject) = > {
const img = new Image();
img.src = src;
img.onload = resolve;
img.onerror = reject;
});
};
Copy the code
Wrong picture
Different browsers have different ways to deal with wrong images. Although there are Alt prompt messages, they are not uniform and beautiful
It is better to give the default error image and listen for the onError event of the image to reassign the value. If you do not want to write one by one, you can listen for the window.addeventListener error to complete the global listening
window.addEventListener(
'error'.function (event) {
var dom = event.target;
if (/img/i.test(dom.nodeName)) {
dom.src = 'xxxx.png'; }},true
);
Copy the code
If you want to add retries for bad images, or block JSP dynamic rendering content, see this article how to gracefully handle image exceptions
Null data is processed by default
Ignoring empty data may lead users to think there is a problem with the system. In general, we should try to avoid empty data. Generally speaking, there are two ways to deal with empty data
Fill with empty
General UI frameworks are now built with the Empty component, which can be used to provide default prompts for common tables or lists with no data after correct communication with products and designs
<template>
<template v-if="list.length"> /* ... */ </template>
<template v-else>
<empty />
</template>
</template>
Copy the code
Hide the whole area
For the authors above, it might be odd to show only a title and the full list if there is no data for the current subitem. Consider deleting the entire section
Semantic tags are preferred
Try to avoid the abuse of non-semantic divs and spans, because search engines are not friendly to capture, maintenance is not intuitive, and using semantic tags can save a lot of code work, here is an example
For example, assume that the function of the button above is to jump to a new page. In the SPA page, we can directly use the router-link provided by vue-Router to jump, while in traditional development, a tag can be nested outside the button to complete the jump
<a href="xxx">
<button>xxx</button>
</a>
<!-- 或者 -->
<router-link to="xxx">
<button>xxx</button>
</router-link>
Copy the code
And it’s easy to do with other browser behaviors, such as right-clicking to open in a new TAB
Operation feedback
Operational feedback is an important indicator to improve user experience, which can be expanded into three parts
The Require feedback
In the process of communicating with the back end, please inform the user of success or failure, and the prompt message must be friendly.
There is a rule here
- Success messages can be defined by the front end, which can be combined with a variety of operation scenarios to achieve more detailed prompts
- For error messages, information such as message returned by the back end is returned
- For 500 error, please change in interceptor
Network connection error, please try again later
“, rather than a string of English messages such as timeout
The element of feedback
Two things are important when weighing a UI framework:
- Component interaction is friendly, such as smooth animation, hover, active and other effects
- Is it friendly for accessible reading
The importance of visible interaction is to make the user feel like they are clicking on a real element, not a static image
For example, in the figure above, at least hover, active and other effects should exist
Waiting for the feedback
Because the communication with the back end is asynchronous and the user’s network is not fixed, loading elements is necessary. Here are two common scenarios
The form submission
Loading can be used for common operations and interactions, so as to prevent users from clicking repeatedly or not knowing whether the user has clicked successfully
Retrieve data
Obtaining Pre-information
On PC, loading elements can be used to reduce users’ anxiety of waiting in order to cover up the scene of obtaining some pre-information when entering the page
The cache
Caching is essentially trading space for time. For clients, more of the bottleneck is time. Here are two common caching scenarios
Component information cache
For example, in the form above, if the user closes the web page by mistake, the experience of filling in the form from scratch is not very good. You can combine the local persistent cache in the state of unsuccessful submission
Here is a simple example (not given to complete the purge of local storage)
<script> import { reactive, watchEffect } from 'vue'; export default { setUp() { const key = 'form'; const form = reactive({ name: '', password: '', }); const set = (key, value) => { localStorage.setItem(key, JSON.stringify(value)); }; const get = () => { const value = localStorage.getItem(key); try { return JSON.parse(value); } catch { return undefined; }}; watchEffect(() => { set(key, form); }); Object.assign(form, get('form')); }}; </script>Copy the code
Interface cache
If you have frequent requests that are time consuming, and the interface itself barely changes, consider interface caching, as shown in a simple code example
Production environments can consider using some axios-request-cache libraries
import axios from 'axios';
const { toString } = Object.prototype;
// Data store
export const cache = {
data: {},
set(key, data) {
this.data[key] = data;
},
get(key) {
return this.data[key];
},
clear(key) {
delete this.data[key]; }};// Create a unique key
export const buildUniqueUrl = (url, method, params = {}, data = {}) = > {
const paramStr = (obj) = > {
if (toString.call(obj) === '[object Object]') {
return JSON.stringify(
Object.keys(obj)
.sort()
.reduce((result, key) = > {
result[key] = obj[key];
returnresult; }, {})); }else {
return JSON.stringify(obj); }}; url +=`?${paramStr(params)}&${paramStr(data)}&${method}`;
return url;
};
// Prevent duplicate requests
export default (options = {}) =>
async (config) => {
const defaultOptions = {
// Set it to 0 and do not clear the cache
time: 0. options, };const index = buildUniqueUrl(config.url, config.method, config.params, config.data);
let responsePromise = cache.get(index);
if(! responsePromise) { responsePromise = (async() = > {try {
const response = await axios.defaults.adapter(config);
return Promise.resolve(response);
} catch (reason) {
cache.clear(index);
return Promise.reject(reason);
}
})();
cache.set(index, responsePromise);
if(defaultOptions.time ! = =0) {
setTimeout(() = >{ cache.clear(index); }, defaultOptions.time); }}// To prevent data source contamination
return responsePromise.then((data) = > JSON.parse(JSON.stringify(data)));
};
Copy the code
Style consistency
There are many parts to style consistency, and it’s not easy to list them all here, but just two common ones
Visual color consistency
Each page has a primary color number. For parts that are not shown in the design or prototype, consider whether they conflict with the primary color number when you do your own work or reference components. It is recommended to read the visual specification, as shown below for an example
In the default Vant component, the default TAB color is # EE0a24, which will cause the page style to be inconsistent because the entire page style is blue
Component interaction consistency
Custom extensions or secondary wraps are common here, again using forms as an example
If we want to customize a component that performs a file upload based on the business, we need to consider consistency issues, such as validation issues, in addition to the implementation of the functionality itself
Here Ant Design presents a red prompt under a form-item that does not meet the criteria, and if we use message or any other prompt, the message will be inconsistent. It is better to follow the custom plug-in approach provided by the official documentation for component development.
pc
Consider minimum layout
Set min-width to prevent elements from crowding together due to insufficient width
body {
/* omit other */
min-width: 1200px;
overflow: auto;
}
Copy the code
Table width
For the table, the width should be different depending on the weight of the field. Try not to use Auto to avoid the visual float caused by the second table width calculation
For information that cannot be omitted, wrap it; otherwise, consider Ellipsis
.ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
Copy the code
Add tip to indicator card
In some Taiwan products, it is easy to meet some professional terms, such as PV and UV, for this kind of professional terms, it is suggested to add a question mark prompt icon, mouse move up to give tips
The above effect is for reference only
Keyboard shortcuts are supported
As shown in the figure above, when using form or input, if you press Enter, make sure that you can perform normal search or submit operations, not only for form submission, but also for some common search scenarios
A good suggestion is to bind the.Enter modifier to any child element that requires submit
<input @keyup.enter="submit" />
Copy the code
SPA routing navigation
For single-page navigation consider using progress bars such as NProgress to add progress notifications to your pages
The mobile terminal
Swipe left and right monitor
I have browsed many H5 pages, but there is basically no support for gesture left and right sliding. However, on many apps, such as Zhihu, you can return to the problem by swiping left from the home page
Here’s a slight suggestion: For the following two cases, you can consider introducing a left slide return
- There are many TAB pages consistent with the above picture, so you can consider making the element slide monitor under TAB
- For some lists and detail pages
Recommend a library source code is also very simple can be based on this library for secondary encapsulation, improve the user experience swipy
Use SVG whenever possible
SVG is an image file format that stands for Scalable Vector Graphics. Xml-based markup language
SVG is vector graphics, and it has many advantages
- SVG is scalable and can be printed with high quality at any resolution
- SVG can be enlarged without degrading image quality
- Easy to modify, can be opened in the notepad software
In the development of mobile terminals, the screens of users’ phones are also different. The previous practice was to choose different pictures for phones with different ratios. However, according to the advantages of SVG above, we can directly choose SVG as the picture
In scenarios where SVG is not appropriate, we can use media queries to select the appropriate high magnification
export const getMultipleImg = (img1, img2) = > {
const mql = window.matchMedia('@media only screen and (-webkit-min-device-pixel-ratio:3)');
if (mql.matches) {
return img2;
}
return img1;
};
Copy the code