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:

  1. Git specification
  2. Engineering specifications
  3. User experience specification
  4. 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 interceptorNetwork 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:

  1. Component interaction is friendly, such as smooth animation, hover, active and other effects
  2. 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