Skip to content

Component Usage FAQ

This document addresses common questions and solutions related to component usage in uni-app development.

Basic Component Issues

Q: Unable to modify component styles

Problem Description: Cannot modify default component styles, or style modifications are ineffective.

Solutions:

  1. Use class selectors to override styles (increase selector specificity):

    css
    /* Increase specificity with parent selector */
    .page .btn {
      background-color: #ff0000;
    }
  2. Use !important to increase style priority:

    css
    .btn {
      background-color: #ff0000 !important;
    }
  3. Use inline styles:

    html
    <button class="btn" style="background-color: #ff0000;">Button</button>
  4. For mini-program native components, use official style variables:

    css
    /* WeChat mini-program button style variables */
    page {
      --button-height: 88rpx;
      --button-background-color: #ff0000;
    }
  5. Use conditional compilation for different platforms:

    css
    /* #ifdef MP-WEIXIN */
    button {
      background-color: #ff0000;
    }
    /* #endif */
    
    /* #ifdef H5 */
    button {
      background-color: #00ff00;
    }
    /* #endif */

Q: Component events not triggering

Problem Description: Bound event handlers are not being triggered.

Solutions:

  1. Check if event names are correct:

    html
    <!-- Correct usage -->
    <button @tap="handleTap">Button</button>
    <button @click="handleClick">Button</button>
    
    <!-- Incorrect usage -->
    <button @tap="handleTap()">Button</button> <!-- Don't call functions in template -->
  2. Check if event handlers are properly defined:

    js
    export default {
      methods: {
        // Correct definition
        handleTap(e) {
          console.log('Button clicked', e);
        }
      }
    }
  3. Check for event bubbling prevention:

    html
    <!-- Prevent event bubbling -->
    <view @tap.stop="handleViewTap">
      <button @tap="handleButtonTap">Button</button>
    </view>
  4. For custom components, ensure events are properly emitted:

    js
    // In child component
    methods: {
      handleClick() {
        this.$emit('myevent', { data: 'some data' });
      }
    }
    html
    <!-- In parent component -->
    <custom-component @myevent="handleMyEvent"></custom-component>
  5. Check for nested component event issues:

    html
    <!-- Use .native modifier to listen to native events on component root element -->
    <custom-component @tap.native="handleTap"></custom-component>

Q: Component display abnormalities

Problem Description: Components display incorrectly, such as wrong size, position, or content.

Solutions:

  1. Check if component properties are correctly set:

    html
    <!-- Correctly set image properties -->
    <image src="/static/logo.png" mode="aspectFit" style="width: 200rpx; height: 200rpx;"></image>
  2. Check if data binding is correct:

    html
    <!-- Ensure title variable exists and has value -->
    <text>{{ title || 'Default Title' }}</text>
  3. Use v-if and v-show to control display:

    html
    <!-- Don't render when content doesn't exist -->
    <view v-if="content">{{ content }}</view>
    
    <!-- Hide but still render when content doesn't exist -->
    <view v-show="content">{{ content }}</view>
  4. Check for style conflicts:

    css
    /* Use namespace to avoid style conflicts */
    .my-component .title {
      font-size: 32rpx;
    }
  5. For mini-program native component layering issues:

    css
    /* Adjust z-index to solve layering issues */
    .cover-view {
      z-index: 10;
    }

Form Component Issues

Q: Input fields cannot get focus

Problem Description: Input, textarea and other input fields cannot get focus normally.

Solutions:

  1. Use focus property:

    html
    <input :focus="isFocus" @blur="handleBlur" />
    js
    export default {
      data() {
        return {
          isFocus: false
        }
      },
      methods: {
        setFocus() {
          this.isFocus = true;
        },
        handleBlur() {
          this.isFocus = false;
        }
      }
    }
  2. Use uni.createSelectorQuery to get element and set focus:

    js
    focusInput() {
      const query = uni.createSelectorQuery().in(this);
      query.select('.input').boundingClientRect(data => {
        // Ensure element exists
        if (data) {
          // Set focus
          uni.createSelectorQuery().in(this).select('.input').fields({
            context: true,
          }, res => {
            res.context && res.context.focus();
          }).exec();
        }
      }).exec();
    }
  3. Check z-index and overlay issues:

    css
    .input-wrapper {
      position: relative;
      z-index: 10; /* Ensure input is on top layer */
    }
  4. Handle keyboard popup issues:

    json
    // pages.json
    {
      "pages": [
        {
          "path": "pages/index/index",
          "style": {
            "app-plus": {
              "softinputMode": "adjustResize",
              "softinputNavBar": "none"
            }
          }
        }
      ]
    }

Q: Form data two-way binding issues

Problem Description: Issues occur when using v-model for two-way data binding.

Solutions:

  1. Correctly use v-model:

    html
    <input v-model="inputValue" />
    js
    export default {
      data() {
        return {
          inputValue: ''
        }
      }
    }
  2. For complex forms, use v-model.lazy to reduce update frequency:

    html
    <input v-model.lazy="inputValue" />
  3. Use value + event instead of v-model:

    html
    <input :value="inputValue" @input="inputValue = $event.target.value" />
  4. For mini-program platforms, handle event object differences:

    html
    <input :value="inputValue" @input="handleInput" />
    js
    methods: {
      handleInput(e) {
        // Compatible with different platform event objects
        this.inputValue = e.detail.value || e.target.value;
      }
    }
  5. For custom components, correctly implement v-model:

    js
    // Custom component
    export default {
      props: {
        value: {
          type: String,
          default: ''
        }
      },
      methods: {
        handleInput(e) {
          const value = e.detail.value;
          this.$emit('input', value);
        }
      }
    }
    html
    <!-- In custom component -->
    <input :value="value" @input="handleInput" />
    
    <!-- Using custom component -->
    <custom-input v-model="inputValue"></custom-input>

Q: Form submission and validation issues

Problem Description: Form validation fails or submission is unsuccessful.

Solutions:

  1. Implement basic form validation:

    js
    methods: {
      submitForm() {
        // Validate form
        if (!this.username) {
          uni.showToast({
            title: 'Please enter username',
            icon: 'none'
          });
          return;
        }
        
        if (this.password.length < 6) {
          uni.showToast({
            title: 'Password must be at least 6 characters',
            icon: 'none'
          });
          return;
        }
        
        // Submit form
        uni.request({
          url: 'https://api.example.com/login',
          method: 'POST',
          data: {
            username: this.username,
            password: this.password
          },
          success: (res) => {
            // Handle success response
          },
          fail: (err) => {
            // Handle error
          }
        });
      }
    }
  2. Use third-party validation library:

    js
    // Using async-validator
    import Schema from 'async-validator';
    
    export default {
      methods: {
        validateForm() {
          const descriptor = {
            username: [
              { required: true, message: 'Please enter username' },
              { min: 3, max: 20, message: 'Username length should be 3-20 characters' }
            ],
            password: [
              { required: true, message: 'Please enter password' },
              { min: 6, message: 'Password must be at least 6 characters' }
            ],
            email: [
              { type: 'email', message: 'Please enter a valid email address' }
            ]
          };
          
          const validator = new Schema(descriptor);
          
          validator.validate(this.formData, (errors, fields) => {
            if (errors) {
              // Show first error
              uni.showToast({
                title: errors[0].message,
                icon: 'none'
              });
            } else {
              // Validation passed, submit form
              this.submitForm();
            }
          });
        }
      }
    }
  3. Handle form reset:

    html
    <form @submit="handleSubmit" @reset="handleReset">
      <input name="username" v-model="formData.username" />
      <input name="password" v-model="formData.password" type="password" />
      <button form-type="submit">Submit</button>
      <button form-type="reset">Reset</button>
    </form>
    js
    methods: {
      handleSubmit(e) {
        // Prevent default submit behavior
        e.preventDefault && e.preventDefault();
        this.validateForm();
      },
      handleReset() {
        this.formData = {
          username: '',
          password: '',
          email: ''
        };
      }
    }
  4. Handle file upload:

    html
    <button @tap="chooseImage">Choose Image</button>
    <image v-if="imageUrl" :src="imageUrl" mode="aspectFit"></image>
    js
    methods: {
      chooseImage() {
        uni.chooseImage({
          count: 1,
          success: (res) => {
            const tempFilePath = res.tempFilePaths[0];
            this.imageUrl = tempFilePath;
            
            // Upload image
            uni.uploadFile({
              url: 'https://api.example.com/upload',
              filePath: tempFilePath,
              name: 'file',
              success: (uploadRes) => {
                const data = JSON.parse(uploadRes.data);
                this.formData.imageId = data.id;
              },
              fail: (err) => {
                uni.showToast({
                  title: 'Image upload failed',
                  icon: 'none'
                });
              }
            });
          }
        });
      }
    }

List Component Issues

Q: scroll-view scrolling issues

Problem Description: scroll-view component cannot scroll normally or scrolling effect is abnormal.

Solutions:

  1. Ensure fixed height is set:

    html
    <scroll-view scroll-y="true" class="scroll-container">
      <!-- Content -->
    </scroll-view>
    css
    .scroll-container {
      height: 500rpx; /* Must set fixed height */
    }
  2. Use scroll-into-view to scroll to specified element:

    html
    <scroll-view 
      scroll-y="true" 
      class="scroll-container" 
      :scroll-into-view="scrollToId"
    >
      <view id="item1" class="item">Item 1</view>
      <view id="item2" class="item">Item 2</view>
      <view id="item3" class="item">Item 3</view>
    </scroll-view>
    js
    export default {
      data() {
        return {
          scrollToId: ''
        }
      },
      methods: {
        scrollToItem(id) {
          this.scrollToId = id;
        }
      }
    }
  3. Listen to scroll events:

    html
    <scroll-view 
      scroll-y="true" 
      class="scroll-container" 
      @scroll="handleScroll"
    >
      <!-- Content -->
    </scroll-view>
    js
    methods: {
      handleScroll(e) {
        const scrollTop = e.detail.scrollTop;
        console.log('Scroll position:', scrollTop);
      }
    }
  4. Solve scroll stuttering issues:

    css
    /* Enable hardware acceleration */
    .scroll-container {
      -webkit-overflow-scrolling: touch; /* iOS smooth scrolling */
      transform: translateZ(0); /* Enable hardware acceleration */
    }
  5. Handle pull-to-refresh and load more:

    html
    <scroll-view 
      scroll-y="true" 
      class="scroll-container" 
      @scrolltolower="loadMore"
      :refresher-enabled="true"
      @refresherrefresh="refresh"
      :refresher-triggered="isRefreshing"
    >
      <!-- Content -->
    </scroll-view>
    js
    export default {
      data() {
        return {
          list: [],
          page: 1,
          isRefreshing: false
        }
      },
      methods: {
        // Load more
        loadMore() {
          this.page++;
          this.loadData();
        },
        // Refresh
        refresh() {
          this.isRefreshing = true;
          this.page = 1;
          this.list = [];
          this.loadData().finally(() => {
            this.isRefreshing = false;
          });
        },
        // Load data
        async loadData() {
          try {
            const res = await uni.request({
              url: `https://api.example.com/list?page=${this.page}`
            });
            if (this.page === 1) {
              this.list = res.data;
            } else {
              this.list = [...this.list, ...res.data];
            }
          } catch (err) {
            uni.showToast({
              title: 'Load failed',
              icon: 'none'
            });
          }
        }
      }
    }

Q: Long list performance issues

Problem Description: Long list rendering is stuttering or memory usage is too high.

Solutions:

  1. Use virtual list optimization:

    html
    <recycle-list class="list" :list="list" :item-size="100">
      <cell v-for="(item, index) in list" :key="index">
        <view class="item">
          <text class="title">{{ item.title }}</text>
          <text class="desc">{{ item.desc }}</text>
        </view>
      </cell>
    </recycle-list>
  2. Paginated data loading:

    js
    export default {
      data() {
        return {
          list: [],
          page: 1,
          pageSize: 20,
          hasMore: true,
          loading: false
        }
      },
      onLoad() {
        this.loadData();
      },
      onReachBottom() {
        if (this.hasMore && !this.loading) {
          this.loadMore();
        }
      },
      methods: {
        async loadData() {
          if (!this.hasMore || this.loading) return;
          
          this.loading = true;
          try {
            const res = await uni.request({
              url: 'https://api.example.com/list',
              data: {
                page: this.page,
                pageSize: this.pageSize
              }
            });
            
            const data = res.data;
            if (this.page === 1) {
              this.list = data.list;
            } else {
              this.list = [...this.list, ...data.list];
            }
            
            this.hasMore = data.hasMore;
            this.page++;
          } catch (err) {
            uni.showToast({
              title: 'Load failed',
              icon: 'none'
            });
          } finally {
            this.loading = false;
          }
        },
        loadMore() {
          this.loadData();
        },
        refresh() {
          this.page = 1;
          this.hasMore = true;
          this.list = [];
          this.loadData();
        }
      }
    }
  3. Use computed properties to filter data:

    js
    export default {
      data() {
        return {
          rawList: [],
          keyword: ''
        }
      },
      computed: {
        filteredList() {
          if (!this.keyword) return this.rawList;
          
          return this.rawList.filter(item => 
            item.title.includes(this.keyword) || 
            item.desc.includes(this.keyword)
          );
        }
      }
    }
  4. Optimize list item rendering:

    html
    <view class="list">
      <view 
        v-for="(item, index) in list" 
        :key="item.id" 
        class="item"
        :class="{ 'even': index % 2 === 0 }"
      >
        <!-- Use simple structure -->
        <text class="title">{{ item.title }}</text>
        <!-- Avoid using complex components in list items -->
      </view>
    </view>
  5. Use v-once to optimize static content:

    html
    <view class="list">
      <view 
        v-for="(item, index) in list" 
        :key="item.id" 
        class="item"
      >
        <!-- Static content rendered only once -->
        <text class="label" v-once>Title:</text>
        <text class="title">{{ item.title }}</text>
      </view>
    </view>

Q: swiper component issues

Problem Description: swiper component switching is abnormal or display is incorrect.

Solutions:

  1. Ensure correct height is set:

    html
    <swiper class="swiper" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
      <swiper-item v-for="(item, index) in banners" :key="index">
        <image :src="item.image" mode="aspectFill" class="swiper-image"></image>
      </swiper-item>
    </swiper>
    css
    .swiper {
      height: 300rpx;
    }
    
    .swiper-image {
      width: 100%;
      height: 100%;
    }
  2. Handle dynamic content loading:

    html
    <swiper 
      class="swiper" 
      :indicator-dots="true" 
      :current="current"
      @change="handleChange"
      v-if="banners.length > 0"
    >
      <swiper-item v-for="(item, index) in banners" :key="index">
        <image 
          :src="item.image" 
          mode="aspectFill" 
          class="swiper-image"
          @load="imageLoaded"
        ></image>
      </swiper-item>
    </swiper>
    js
    export default {
      data() {
        return {
          banners: [],
          current: 0,
          imagesLoaded: 0
        }
      },
      methods: {
        handleChange(e) {
          this.current = e.detail.current;
        },
        imageLoaded() {
          this.imagesLoaded++;
        }
      }
    }
  3. Handle circular scrolling issues:

    html
    <swiper 
      class="swiper" 
      :indicator-dots="true" 
      :autoplay="true" 
      :circular="true"
      :interval="3000" 
      :duration="500"
    >
      <!-- Content -->
    </swiper>
  4. Handle stuttering issues:

    html
    <swiper 
      class="swiper" 
      :indicator-dots="true" 
      :autoplay="true" 
      :interval="3000" 
      :duration="500"
      :display-multiple-items="1"
      :next-margin="nextMargin"
      :previous-margin="previousMargin"
    >
      <!-- Content -->
    </swiper>
    js
    export default {
      data() {
        return {
          nextMargin: '50rpx',
          previousMargin: '50rpx'
        }
      }
    }

Custom Component Issues

Q: Component communication issues

Problem Description: Parent-child components cannot communicate normally or data transfer fails.

Solutions:

  1. Use props to pass data to child components:

    html
    <!-- Parent component -->
    <child-component :title="title" :list="list"></child-component>
    js
    // Child component
    export default {
      props: {
        title: {
          type: String,
          default: 'Default Title'
        },
        list: {
          type: Array,
          default: () => []
        }
      }
    }
  2. Use events to pass data to parent components:

    js
    // Child component
    methods: {
      sendData() {
        this.$emit('update', { value: this.value });
      }
    }
    html
    <!-- Parent component -->
    <child-component @update="handleUpdate"></child-component>
    js
    // Parent component
    methods: {
      handleUpdate(data) {
        console.log('Received data from child component:', data);
      }
    }
  3. Use ref to directly access child components:

    html
    <!-- Parent component -->
    <child-component ref="childComp"></child-component>
    js
    // Parent component
    methods: {
      callChildMethod() {
        this.$refs.childComp.childMethod();
      }
    }
  4. Use provide/inject for deep component communication:

    js
    // Ancestor component
    export default {
      provide() {
        return {
          theme: this.theme,
          updateTheme: this.updateTheme
        };
      },
      data() {
        return {
          theme: 'light'
        }
      },
      methods: {
        updateTheme(newTheme) {
          this.theme = newTheme;
        }
      }
    }
    js
    // Descendant component
    export default {
      inject: ['theme', 'updateTheme'],
      methods: {
        changeTheme() {
          this.updateTheme('dark');
        }
      }
    }
  5. Use Vuex or uni-app global state management:

    js
    // store.js
    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        count: 0,
        user: null
      },
      mutations: {
        increment(state) {
          state.count++;
        },
        setUser(state, user) {
          state.user = user;
        }
      },
      actions: {
        login({ commit }, userData) {
          // Async login
          return new Promise((resolve, reject) => {
            uni.request({
              url: 'https://api.example.com/login',
              method: 'POST',
              data: userData,
              success: (res) => {
                commit('setUser', res.data.user);
                resolve(res.data);
              },
              fail: reject
            });
          });
        }
      }
    });
    js
    // Using in components
    import { mapState, mapMutations, mapActions } from 'vuex';
    
    export default {
      computed: {
        ...mapState(['count', 'user'])
      },
      methods: {
        ...mapMutations(['increment']),
        ...mapActions(['login']),
        async handleLogin() {
          try {
            await this.login({ username: 'test', password: '123456' });
            uni.showToast({ title: 'Login successful' });
          } catch (err) {
            uni.showToast({ title: 'Login failed', icon: 'none' });
          }
        }
      }
    }

Q: Component lifecycle issues

Problem Description: Component lifecycle hooks don't execute as expected or execution order is abnormal.

Solutions:

  1. Understand component lifecycle order:

    js
    export default {
      beforeCreate() {
        console.log('beforeCreate');
      },
      created() {
        console.log('created');
      },
      beforeMount() {
        console.log('beforeMount');
      },
      mounted() {
        console.log('mounted');
      },
      beforeUpdate() {
        console.log('beforeUpdate');
      },
      updated() {
        console.log('updated');
      },
      beforeDestroy() {
        console.log('beforeDestroy');
      },
      destroyed() {
        console.log('destroyed');
      }
    }
  2. Use onReady instead of mounted for view rendering completion logic:

    js
    export default {
      mounted() {
        // View might not be fully rendered yet
        console.log('mounted');
      },
      onReady() {
        // View has been fully rendered
        console.log('onReady');
        this.initChart();
      }
    }
  3. Handle cleanup work when component unmounts:

    js
    export default {
      data() {
        return {
          timer: null
        }
      },
      mounted() {
        // Set timer
        this.timer = setInterval(() => {
          console.log('Timer executing');
        }, 1000);
      },
      beforeDestroy() {
        // Clear timer
        if (this.timer) {
          clearInterval(this.timer);
          this.timer = null;
        }
      }
    }
  4. Use nextTick to handle operations after view updates:

    js
    methods: {
      updateData() {
        this.list = [...this.list, { id: Date.now(), text: 'New Item' }];
        
        // Wait for view update
        this.$nextTick(() => {
          // View has been updated
          const lastItem = document.querySelector('.item:last-child');
          if (lastItem) {
            lastItem.scrollIntoView({ behavior: 'smooth' });
          }
        });
      }
    }
  5. Understand the difference between page and component lifecycles:

    js
    export default {
      // Vue component lifecycle
      created() {
        console.log('Component created');
      },
      mounted() {
        console.log('Component mounted');
      },
      
      // uni-app page lifecycle
      onLoad() {
        console.log('Page onLoad');
      },
      onShow() {
        console.log('Page onShow');
      },
      onReady() {
        console.log('Page onReady');
      },
      onHide() {
        console.log('Page onHide');
      },
      onUnload() {
        console.log('Page onUnload');
      }
    }

Q: Component reuse and performance issues

Problem Description: Component reuse leads to performance degradation or state confusion.

Solutions:

  1. Use key attribute to ensure proper component reuse:

    html
    <custom-component 
      v-for="(item, index) in list" 
      :key="item.id" 
      :data="item"
    ></custom-component>
  2. Avoid complex calculations in templates:

    html
    <!-- Not recommended -->
    <view>{{ getComplexData(item) }}</view>
    
    <!-- Recommended -->
    <view>{{ item.processedData }}</view>
    js
    export default {
      computed: {
        processedList() {
          return this.list.map(item => ({
            ...item,
            processedData: this.getComplexData(item)
          }));
        }
      },
      methods: {
        getComplexData(item) {
          // Complex calculation
          return result;
        }
      }
    }
  3. Use keep-alive to cache component state:

    html
    <keep-alive>
      <component :is="currentComponent"></component>
    </keep-alive>
  4. Use v-show instead of frequently toggled v-if:

    html
    <!-- Use v-show for frequent toggling -->
    <view v-show="isVisible" class="panel">Content</view>
    
    <!-- Use v-if when condition rarely changes -->
    <view v-if="isLoggedIn" class="user-panel">User Info</view>
  5. Use functional components to optimize simple components:

    js
    // Functional component
    Vue.component('my-component', {
      functional: true,
      props: {
        title: String
      },
      render(h, context) {
        return h('view', {
          class: 'my-component'
        }, [
          h('text', context.props.title)
        ]);
      }
    });

Third-party Component Issues

Q: uni-ui component usage issues

Problem Description: Issues encountered when using uni-ui component library.

Solutions:

  1. Correctly install and import uni-ui:

    js
    // Install
    // npm install @dcloudio/uni-ui
    
    // Global registration in main.js
    import uniCard from '@dcloudio/uni-ui/lib/uni-card/uni-card.vue'
    Vue.component('uni-card', uniCard)
    
    // Or import on demand in components
    import { uniCard } from '@dcloudio/uni-ui'
    export default {
      components: {
        uniCard
      }
    }
  2. Handle easycom configuration:

    json
    // pages.json
    {
      "easycom": {
        "autoscan": true,
        "custom": {
          "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
        }
      }
    }
  3. Handle style issues:

    js
    // Import base styles in App.vue
    <style>
    @import '@dcloudio/uni-ui/lib/uni-scss/index.scss';
    </style>
  4. Handle component events:

    html
    <uni-calendar 
      :insert="false"
      :lunar="true"
      :start-date="'2019-3-2'"
      :end-date="'2019-5-20'"
      @change="change"
      @confirm="confirm"
    />
    js
    export default {
      methods: {
        change(e) {
          console.log('Date changed', e);
        },
        confirm(e) {
          console.log('Confirm selection', e);
        }
      }
    }
  5. Custom themes:

    scss
    // uni.scss
    $uni-primary: #007aff;
    $uni-success: #4cd964;
    $uni-warning: #f0ad4e;
    $uni-error: #dd524d;

Q: Map component issues

Problem Description: Issues with display or interaction when using map components.

Solutions:

  1. Correctly set map dimensions:

    html
    <map
      id="map"
      class="map"
      :latitude="latitude"
      :longitude="longitude"
      :markers="markers"
      :scale="scale"
    ></map>
    css
    .map {
      width: 100%;
      height: 300px;
    }
  2. Handle map controls:

    html
    <map
      id="map"
      class="map"
      :latitude="latitude"
      :longitude="longitude"
      :markers="markers"
      :scale="scale"
      :show-location="true"
      :enable-zoom="true"
      :enable-scroll="true"
      @markertap="onMarkerTap"
      @regionchange="onRegionChange"
    ></map>
    js
    export default {
      data() {
        return {
          latitude: 39.909,
          longitude: 116.39742,
          scale: 16,
          markers: [{
            id: 1,
            latitude: 39.909,
            longitude: 116.39742,
            title: 'Marker',
            iconPath: '/static/marker.png',
            width: 32,
            height: 32
          }]
        }
      },
      methods: {
        onMarkerTap(e) {
          console.log('Marker tapped', e);
        },
        onRegionChange(e) {
          console.log('Map region changed', e);
        }
      }
    }
  3. Use map context:

    js
    export default {
      data() {
        return {
          mapContext: null
        }
      },
      onReady() {
        // Create map context
        this.mapContext = uni.createMapContext('map', this);
      },
      methods: {
        moveToLocation() {
          // Move to current location
          this.mapContext.moveToLocation();
        },
        getCenterLocation() {
          // Get center location
          this.mapContext.getCenterLocation({
            success: (res) => {
              console.log('Center location', res.latitude, res.longitude);
            }
          });
        }
      }
    }
  4. Handle permission issues:

    js
    export default {
      onLoad() {
        // Check location permission
        uni.getSetting({
          success: (res) => {
            if (!res.authSetting['scope.userLocation']) {
              uni.authorize({
                scope: 'scope.userLocation',
                success: () => {
                  this.initMap();
                },
                fail: () => {
                  uni.showModal({
                    title: 'Notice',
                    content: 'Location permission is required to use map features',
                    confirmText: 'Go to Settings',
                    success: (res) => {
                      if (res.confirm) {
                        uni.openSetting();
                      }
                    }
                  });
                }
              });
            } else {
              this.initMap();
            }
          }
        });
      },
      methods: {
        initMap() {
          // Initialize map
        }
      }
    }
  5. Handle platform differences:

    js
    export default {
      data() {
        return {
          // Different map configurations for different platforms
          mapConfig: {
            // #ifdef MP-WEIXIN
            controls: [{
              id: 1,
              position: {
                left: 10,
                top: 10,
                width: 40,
                height: 40
              },
              iconPath: '/static/location.png',
              clickable: true
            }],
            // #endif
            
            // #ifdef APP-PLUS
            polyline: [{
              points: [
                { latitude: 39.909, longitude: 116.39742 },
                { latitude: 39.90, longitude: 116.39 }
              ],
              color: '#FF0000DD',
              width: 4
            }]
            // #endif
          }
        }
      }
    }

Common Issue Troubleshooting Process

When encountering component issues, follow these steps for troubleshooting:

  1. Check basic configuration:

    • Confirm components are correctly imported and registered
    • Check if property and event names are correct
    • Confirm data binding is correct
  2. Check console errors:

    • Look for error messages in console
    • Analyze error stack to locate issues
    • Check warning messages
  3. Use developer tools:

    • Use Vue Devtools to check component state
    • Use mini-program developer tools to debug components
    • Use breakpoint debugging to trace execution flow
  4. Simplify the problem:

    • Create minimal reproduction example
    • Gradually remove complex logic to find root cause
    • Try using basic components instead of complex ones

Component Debugging Techniques

Debugging Custom Components

  1. Use console.log to output key information:

    js
    export default {
      props: {
        value: String
      },
      watch: {
        value(newVal, oldVal) {
          console.log('value changed:', oldVal, '->', newVal);
        }
      },
      mounted() {
        console.log('Component mounted, props:', this.$props);
      },
      updated() {
        console.log('Component updated');
      }
    }
  2. Use Vue Devtools for debugging:

    • Use Vue Devtools in H5 to inspect component tree
    • View component props, data, computed properties
    • Monitor event triggers
  3. Add debug styles:

    css
    .debug-component {
      border: 1px solid red;
    }
    html
    <view class="my-component" :class="{ 'debug-component': isDebug }">
      <!-- Component content -->
    </view>
  4. Use conditional breakpoints:

    js
    methods: {
      handleClick() {
        // Set breakpoint under specific conditions
        if (this.count > 5) {
          console.log('Breakpoint location'); // Set breakpoint here
        }
      }
    }

Debugging Third-party Components

  1. Check component documentation and examples:

    • Read official documentation to understand component usage
    • Refer to example code for correct usage
    • Check common issues and solutions
  2. Check version compatibility:

    • Confirm component version is compatible with framework version
    • Check changelog for updates
    • Try upgrading or downgrading component version
  3. View component source code:

    • Analyze component implementation principles
    • Understand component internal working mechanisms
    • Find potential problem points
  4. Create simplified test cases:

    • Test components in new projects
    • Gradually add complexity to find problem trigger conditions
    • Exclude interference from other project factors

Best Practices

Component Design Principles

  1. Single Responsibility Principle:

    • Each component should only be responsible for one function
    • Avoid creating large and comprehensive complex components
    • Split complex components into multiple simple components
  2. Reusability:

    • Design general components rather than specific scenario components
    • Use props to configure component behavior
    • Avoid tight coupling between components
  3. Testability:

    • Component logic should be clear and easy to test
    • Avoid side effects, use pure functions
    • Separate business logic from UI rendering
  4. Maintainability:

    • Component structure should be clear with concise code
    • Add necessary comments and documentation
    • Follow consistent naming and style conventions

Component Performance Optimization

  1. Avoid unnecessary rendering:

    • Use v-once to render static content
    • Use v-if and v-show appropriately
    • Use key to optimize list rendering
  2. Reduce computation:

    • Use computed to cache calculation results
    • Avoid complex calculations in templates
    • Use watch to monitor data changes
  3. Lazy loading:

    • Use dynamic components for on-demand loading
    • Use v-if to conditionally render non-critical components
    • Implement component lazy loading
  4. Optimize update mechanisms:

    • Use immutable data patterns
    • Avoid deeply nested data structures
    • Use Object.freeze to freeze immutable objects

Component Library Development

  1. Unified design specifications:

    • Define consistent visual styles
    • Unified interaction patterns
    • Consistent naming conventions
  2. Good documentation:

    • Detailed API descriptions
    • Rich example code
    • Frequently asked questions
  3. Version management:

    • Follow semantic versioning standards
    • Maintain detailed changelogs
    • Consider backward compatibility
  4. Test coverage:

    • Unit tests ensure functionality correctness
    • Visual regression tests ensure style consistency
    • Cross-platform compatibility testing

Reference Resources

For more component guidance, refer to the API Reference and Best Practices Guide.

一次开发,多端部署 - 让跨平台开发更简单