web前端指南

website·Indexed 31 days ago

https://note.qscoding.com/

A collection of technical guides and notes covering web frontend development, including JavaScript, Vue 3, Vite, Flutter, Docker, and GitHub Actions. Features practical tutorials on i18n configuration, waterfall layouts, TinyMCE integration, and Flutter e-commerce app development.

Tokens
14.2K
Snippets
76
Records
87
Agent score
50%

What's inside web前端指南

  1. Manage Node.js versions with nvm

    Install, uninstall, and switch between different Node.js versions using the Node Version Manager (nvm).
    # Install latest stable version
    nvm install stable
    
    # Install specific version
    nvm install <version>
    
    # Uninstall specific version
    nvm uninstall <version>
    
    # Switch to a specific version
    nvm use <version>
    
    # List installed versions
    nvm ls
    
    # Set default Node version
    nvm alias default <version>
    
    # Fix for nvm not found in shell (add to ~/.bashrc or ~/.zshrc):
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
  2. Generate and configure multiple Git SSH keys

    Generate separate SSH keys for different Git hosts (e.g., GitHub and Gitee) and configure the SSH config file to use the correct identity file for each host.
    # 1. Generate keys
    ssh-keygen -t rsa -C 'email' -f ~/.ssh/gitee_id_rsa
    ssh-keygen -t rsa -C 'email' -f ~/.ssh/github_id_rsa
    
    # 2. Configure ~/.ssh/config
    # Add the following to ~/.ssh/config:
    Host gitee.com
      HostName gitee.com
      PreferredAuthentications publickey
      IdentityFile ~/.ssh/gitee_id_rsa
    
    Host github.com
      HostName github.com
      PreferredAuthentications publickey
      IdentityFile ~/.ssh/github_id_rsa
    
    # 3. Test connections
    ssh -T git@gitee.com
    ssh -T git@github.com
  3. Manually build and push a Docker image to Alibaba Cloud Registry

    To manually build a Docker image and push it to the Alibaba Cloud Container Registry, you must authenticate with the registry, build the image using a local Dockerfile, and then push the tagged image to the remote repository.
    # Login to Alibaba Cloud Docker Registry
    docker login --username=**** registry.cn-shenzhen.aliyuncs.com
    
    # Build the image based on the project's Dockerfile
    docker build -t registry.cn-shenzhen.aliyuncs.com/xxxx/image-name:v1 .
    
    # Push the image to the Registry
    docker push registry.cn-shenzhen.aliyuncs.com/xxxx/image-name:v1
  4. Design efficient API interfaces for frontend-backend collaboration

    Follow RESTful principles to improve collaboration efficiency. Key considerations for API design include:

    • Versioning and Compatibility: Ensure backward compatibility when modifying interfaces. Use an option object to add parameters for specific scenarios without breaking existing implementations.
    • Strict Data Typing: Strictly constrain data types for request parameters and response bodies. For example, return numeric values as numbers (e.g., page=3) rather than strings (page='3') to avoid unnecessary type conversion in the frontend.
  5. Implement a Waterfall layout in Vue 3

    A waterfall layout is ideal for lists where items have inconsistent heights (e.g., images of different sizes or varying text lengths). This implementation uses a pure JavaScript approach with absolute positioning to place items in the shortest available column.
    <script setup lang="ts">
    import { ref, onMounted, onBeforeUnmount, withDefaults } from 'vue';
    
    const props = withDefaults(
      defineProps<{
        list: any[];
        columnWidth?: number; // Column width
        columnGap?: number; // Gap between columns
      }>(),
      {
        columnWidth: 240,
        columnGap: 24,
      }
    );
    
    const wrapper = ref<HTMLElement | null>(null);
    const content = ref<HTMLElement | null>(null);
    const flowHeight: number[] = [];
    
    const flowDraw = () => {
      if (!content.value) return;
      
      const columnCount = getColumnCount();
      flowHeight.length = columnCount;
      for (let i = 0; i < columnCount; i++) {
        flowHeight[i] = 0;
      }
    
      const itemW = props.columnWidth + props.columnGap;
      content.value.style.width = itemW * columnCount - props.columnGap + 'px';
    
      const doms = content.value.querySelectorAll('.WaterfallItem');
      doms.forEach((dom: any) => {
        const minIdx = getMinIndex(flowHeight);
        dom.style.left = `${minIdx * itemW}px`;
        dom.style.top = `${flowHeight[minIdx]}px`;
        flowHeight[minIdx] += dom.offsetHeight;
      });
      
      content.value.style.height = Math.max(...flowHeight) + 'px';
    };
    
    const getColumnCount = (): number => {
      if (!wrapper.value) return 0;
      const itemW = props.columnWidth + props.columnGap;
      const num = (wrapper.value.offsetWidth + props.columnGap) / itemW;
      return Math.min(Math.floor(num), props.list.length);
    };
    
    const getMinIndex = (list: number[]) => {
      const min = Math.min(...list);
      return list.indexOf(min);
    };
    
    let timer: number | null = null;
    const onResize = () => {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      timer = setTimeout(() => {
        flowDraw();
      }, 300);
    };
    
    onMounted(() => {
      flowDraw();
      window.addEventListener('resize', onResize);
    });
    
    onBeforeUnmount(() => {
      window.removeEventListener('resize', onResize);
    });
    </script>
    
    <template>
      <div class="WaterfallList" ref="wrapper">
        <div class="WaterfallContent" ref="content">
          <div class="WaterfallItem" v-for="(item, index) in list" :key="index">
            <slot name="item" :index="index" :item="item"></slot>
          </div>
        </div>
      </div>
    </template>
    
    <style lang="sass" scoped>
    .WaterfallContent
      margin-left: auto
      margin-right: auto
      position: relative
    
    .WaterfallItem
      padding-bottom: 24px
      width: v-bind("columnWidth + 'px'")
      position: absolute
      top: 0
      left: 0
    </style>
  6. Display SVG icons using flutter_svg

    To use SVG icons in a Flutter project, download the SVG files (e.g., from iconfont.cn) and place them in the assets/svg directory. You must declare the assets in pubspec.yaml and use the flutter_svg package to render them via SvgPicture.asset.
    # pubspec.yaml
    assets:
      - assets/svg/
    flutter pub add flutter_svg
    import 'package:flutter_svg/svg.dart';
    
    Padding(
        padding: const EdgeInsets.symmetric(vertical: 4),
        child: SvgPicture.asset('assets/svg/category_phone.svg', height: 35),
    )
    
  7. Initialize and start a new Hexo project

    Create a new Hexo blog instance, install dependencies, and launch the local development server to preview the site.
    hexo init <project_name>
    cd <project_name>
    npm install
    hexo s
  8. Initialize a Git project and push to a remote repository

    Steps to create a new local directory, initialize it as a Git repository, and push the initial commit to a remote server (e.g., GitHub).
    mkdir drawingboard
    cd drawingboard
    git init
    touch README.md
    git add README.md
    git commit -m "first commit"
    git remote add origin https://github.com/jsdawn/xxx.git
    git push -u origin master
    
    # Verify remote URL
    git remote -v
  9. Create and run a Flutter project

    Create a new project using the CLI. The recommended naming convention for project folders is underscore-separated (snake_case). To run the project, ensure a simulator (iOS/Android) is active or use web browser mode, then execute the run command.
    # Create project
    flutter create flutter_demo
    
    # Run project
    flutter run
  10. Implement upload progress bar with customRequest

    When using customRequest, the file.percent value remains 0 unless manually updated. To implement a progress bar, use the onUploadProgress callback from Axios and call e.onProgress({ percent }) within the customRequest function.
    // 1. API wrapper supporting progress callback
    export const uploadApi = ({ file, onUploadProgress }) => {
      const formData = new FormData();
      formData.append('file', file);
    
      return axios({
        url: '/api/upload',
        method: 'POST',
        data: formData,
        headers: { 'Content-type': 'multipart/form-data' },
        onUploadProgress, // Pass the callback to axios
      });
    };
    
    // 2. customRequest implementation
    const customUpload = (e) => {
      uploadApi({
        file: e.file,
        onUploadProgress: (ev) => {
          // Calculate percentage: (loaded / total) * 100
          const percent = (ev.loaded / ev.total) * 100;
          // Update the component's progress bar
          e.onProgress({ percent });
        },
      })
      .then((res) => e.onSuccess(res.data, e))
      .catch((err) => e.onError(err));
    };
  11. Use the v-lazy directive in a Vue 3 component

    To use the useLazyLoad hook, call it within the <script setup> block to define the directive variable. Apply the directive using v-lazy on elements that have a data-src attribute.
    <template>
      <div>
        <img data-src="http://example.com/img1.jpg" v-lazy />
        <img data-src="http://example.com/img2.jpg" v-lazy />
      </div>
    </template>
    
    <script setup lang="ts">
    import { useLazyLoad } from './hooks/useLazyLoad';
    // Register the v-lazy directive
    const vLazy = useLazyLoad();
    </script>
  12. Use the const keyword in Dart classes

    When using const constructors in Dart, the following rules apply:

    1. All member properties of the class must be marked as final.
    2. Objects created with the const modifier have immutable properties that cannot be modified.
    3. Any values passed into a const constructor must themselves be const objects.