ClamView introduction

background

Before my former company, interface problems often, basic each interface will be a problem, which requires we have to do front end for each interface error messages to remind, very trouble, of course it is also necessary, so I think do a component can help our automatic processing and display the error message and was developed using Flutter, So it should be widget. Then I did VUE and applets, and I thought if I could bring that solution to VUE, so I came up with this

function

  • Loading is displayed as a skeleton screen, and the transition can be silky smooth until loading is complete
  • An error message is displayed

Look at the effect

The principle of

In general, when we request the interface and then render the data, we first determine whether there is data to render different views, such as a loaded booth map, a placeholder map of empty data, and present the data when there is data.

ClamView’s idea is to give a data to the rendered template before the data loading is complete, and then set the background color and font color to the span, IMG and other tags that are responsible for displaying the data to achieve the effect of “skeleton”. After the data request is completed, animation is used to hide the skeleton and complete the transition.

code

  • ClamView.tsx

    ClamView needs to pass in a ResponseBean to determine the state of the current data, and a dummy data emptyData to hold up your SPAN tag

import { defineComponent,computed } from 'vue';
import {ResponseBean} from "bdjf_http";
import './clam_view.css'
import './skeleton.css'

/** * Define four ClamView states * 1. LOADING res is empty or res.code === -100 EMPTY res.code === 0 and res.data is null * 3. SHOW res.code === 0 and res.data is not null * 4. ERROR res.code! / * * = = 0
type ViewStatusType = 'LOADING'|'EMPTY'|'SHOW'|'ERROR';

export default defineComponent({
    name:'ClamView'.props: {res: {
            type:ResponseBean,
            default:() = >{
                // A loading is displayed by default
                return newResponseBean().loading(); }},showLoading: {type: Boolean.default:() = >{
                return false; }},emptyText: {type: String.default:() = >{
                return 'No data at present'; }},emptyData: {type:Object.default:() = >{
                return{}}},noPackage: {type: Boolean.default:() = >{
                return false; }}},setup(props,{ slots }) {

        // How to display the res according to the state
        const viewStatusAdapter = (response: ResponseBean): ViewStatusType= > {
            // console.log('----viewStatusAdapter----',response)
            if (props.showLoading) {
                return "LOADING";
            }
            if(! response) {return "LOADING";
            }
            switch (response.code) {
                case 0:
                    if(! response.data || response.data.length ===0) {
                        return "EMPTY";
                    } else {
                        return "SHOW";
                    }
                case -100:
                    return "LOADING";
                default:
                    return "ERROR"; }}// Use computed arithmetic
        const viewStatus = computed<ViewStatusType>(() = >{
            return viewStatusAdapter(props.res)
        })

        const noDataView = (text:string) = >{
            return (
                <div class="empty_view col-center item-center">
                    {text}
                </div>)}const emptyView = () = >{
            if(viewStatus.value === 'EMPTY') {return slots.empty?slots.empty():noDataView(props.emptyText);
            }
        }

        const errorView = () = >{
            if(viewStatus.value === 'ERROR') {return slots.error?slots.error():noDataView(props.res.msg);
            }
        }



        return () = > {
            if(viewStatus.value === 'EMPTY') {return emptyView();
            }else if(viewStatus.value === 'ERROR') {return errorView();
            }else {
                // When noPackage is false, ClamView will create a layer of divs outside of slots.
                // When true, div will not be wrapped and will be toggled via the vClass attribute to the desired local binding style
                if(props.noPackage){
                    return slots.default({
                        data:viewStatus.value==='LOADING'? props.emptyData:props.res.data,vClass:viewStatus.value==='LOADING'?'skeleton-view-empty-view':'skeleton-view-default-view'})}else {
                    return (
                        <div  class={viewStatus.value= = ='LOADING'? 'skeleton-view-empty-view':'skeleton-view-default-view'} >
                            {slots.default({
                                data:viewStatus.value==='LOADING'?props.emptyData:props.res.data
                            })}
                        </div>)}}}}})Copy the code
  • skeleton.css

/** Normal style, set transition to smooth transition */
.skeleton-view-default-view span..skeleton-view-default-view a..skeleton-view-default-view img
{
    transition: all .7s ease;
    background-color: rgba(0.0.0.0);
}


< span, a, img > < span, a, img > < span, a, img > < span, a, img > < span, a, img
.skeleton-view-empty-view {
    pointer-events: none;
}
.skeleton-view-empty-view span..skeleton-view-empty-view a {
    color: rgba(0.0.0.0) ! important;
    border-radius: 2px;
    background: linear-gradient(-45deg.#F5F5F5 0%.#DCDCDC 25%.#F5F5F5 50%.#DCDCDC 75%.#F5F5F5 100%
    );
    animation: gradientBG 4s ease infinite;
    background-size: 400% 400%;
    background-color:#DCDCDC;
    transition: all 1s ease;
}

.skeleton-view-empty-view img {
    /* Here is a small transparent image */
    content: url(. /.. /assets/img/no_url.png);
    border-radius: 2px;
    background: linear-gradient(-45deg.#F5F5F5 0%.#DCDCDC 25%.#F5F5F5 50%.#DCDCDC 75%.#F5F5F5 100%
    );
    animation: gradientBG 4s ease infinite;
    background-size: 400% 400%;
    background-color:#DCDCDC;
    transition: all 1s ease;
}
@keyframes gradientBG {
    0% {
        background-position: 100% 100%;
    }
    50% {
        background-position: 0% 0%;
    }
    100% {
        background-position: 100% 100%; }}Copy the code
  • clam_view.css
.clam-box{
    width: 100%;
    height: 100%;
}
.empty_view{
    padding-top: 100px;
    width: 100%;
    height: 100%;
    padding-bottom: 100px;
}
.empty_img{
    width: 310px;
    height: 218px;
}
.trip_text{
    font-size: 28px;
    color: # 999999;
}
Copy the code

use

<template>
  <div class="home col">
    <clam-view :res="response" v-slot="{data}" :empty-data="emptyData">
      <p><span>{{data.name}}</span></p>
      <p>Home</p>
      <router-link to="/about" >{{data.route}}</router-link>
    </clam-view>
  </div>
</template>
Copy the code
<script lang="ts">
import { defineComponent,reactive,toRefs,onMounted } from 'vue';
import {ResponseBean} from 'bdjf_http'

export default defineComponent({
  name: 'Home'.setup(){

    const state = reactive({
      response:new ResponseBean().loading()
    })

    onMounted(() = >{
      setTimeout(() = >{
        state.response = new ResponseBean(0.' ', {name:'Home'.route:'About'})},2500)})const emptyData = {
      name:'station text'.route:'station text'
    }

    return {
      ...toRefs(state),
      emptyData
    }
  }
});
</script>

<style scoped>
</style>
Copy the code

Cooperate with bdjf_http

If you use it with bdjf_http, you can do what you need with very little code. Learn about bDJf_http here

post(API.getData())
.then(res= > state.response = res;)
Copy the code