国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】

這篇具有很好參考價值的文章主要介紹了移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

移動端

antv f2

版本問題

jsx

經(jīng)典配置

自動配置

vue

使用

bar?

radar

PC端

antv

antv G6

Vue2

scss

Echarts

Vue3

radar

React

原生echarts+TS

ListChart(列表切換echarts圖表,同類數(shù)據(jù)為x軸的bar)

ListChart.tsx

ListChart.css

ListChartUtil.tsx

Recharts???????

D3


  1. 體量:Echarts支持按需引用
  2. 靈活度:ECharts<G2<D3
  3. 使用難度:Echart≈G2PLot<G2<D3
  4. 場景:畫三維圖用Three,三維地圖AntV的L7|L7Plot也可以做到,畫二維圖用ECharts或者G2、G2Plot均可

移動端

antv f2

移動端使用antv f2???????

vue使用antv f2

yarn add @antv/f2

yarn add @antv/f-vue

npm install @antv/f2 --save

npm install @antv/f-vue --save

//配置 F2 的 JSX 編譯

npm install @babel/plugin-transform-react-jsx --save-dev

版本問題

目前vue+vite/webpack(antv ?4/5版本)都無法配置成功,因為找不到實例方法,改成3.x版本即可

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

?移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript??

jsx

F2 使用 JSX 語法來構建圖表,所以需要在運行前對 JSX 語法進行編譯, JSX 更多細節(jié)可參考 React 的官方文檔?JSX 簡介

BabelTypeScript 都可以編譯 JSX 語法,并且在編譯時 JSX 語法時,會有 2 種編譯模式,在實際項目中可根據(jù)自己實際情況選擇和使用

經(jīng)典配置

如果希望在 Vue 3 組件中使用普通的 JSX 語法,可以選擇經(jīng)典的配置方式。這種情況下,需要設置 jsxFactoryjsxFragmentFactory 選項。以下是示例的 tsconfig.json 文件:

{
  "compilerOptions": {
    "jsx": "preserve", // 保留 JSX 語法
    "jsxFactory": "jsx", // 指定 JSX 的工廠函數(shù)
    "jsxFragmentFactory": "Fragment" // 指定 JSX 片段的工廠函數(shù)
  }
}

在這種配置下,需要確保的 Vue 組件中使用的 JSX 工廠函數(shù)和片段工廠函數(shù)與你在配置中指定的名稱相匹配。

自動配置

如果想要使用自動化的 JSX 語法,可以使用 jsxjsxImportSource 選項。這種情況下,可以將 AntV F2 的組件庫作為 JSX 的導入來源。以下是示例的 tsconfig.json 文件:

{
  "compilerOptions": {
    "jsx": "react-jsx", // 使用 React 的 JSX 語法
    "jsxImportSource": "@antv/f2" // 指定 JSX 的導入來源
  }
}

???????在這種配置下,可以在 Vue 組件中使用類似 React 的 JSX 語法,不過需要確保在組件中導入了所需的 AntV F2 組件。

選擇哪種配置取決于你更喜歡的語法和使用方式。如果使用經(jīng)典配置,可以繼續(xù)使用普通的 JSX 語法;如果使用自動配置,可以借助 AntV F2 提供的 JSX 語法來創(chuàng)建圖表組件。

vue

vue 默認是不支持直接在組件的 <script> 中使用 JSX 語法的。

如果你不想使用 JSX,你可以將組件的 <script> 部分改為使用 Vue 的選項式 API 或 Composition API (<script setup>)來定義組件邏輯(響應式函數(shù)和鉤子函數(shù))

使用

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

bar?
<script setup lang="ts">
import { onMounted } from 'vue'

import * as F2 from '@antv/f2'

const data: any = [
  { genre: 'Sports', sold: 275 },
  { genre: 'Strategy', sold: 115 },
  { genre: 'Action', sold: 120 },
  { genre: 'Shooter', sold: 350 },
  { genre: 'Other', sold: 150 }
]

onMounted(() => {
  setTimeout(() => {
    drawChart()
  }, 1000)
})

function drawChart() {
    // Step 1: 創(chuàng)建 Chart 對象
    const chart = new F2.Chart({
      id: 'container',
      pixelRatio: window.devicePixelRatio // 指定分辨率
    })
    console.log(chart, '---chart')

    // Step 2: 載入數(shù)據(jù)源
    console.log(data, '---data')
    chart.source(data)

    // Step 3:創(chuàng)建圖形語法,繪制柱狀圖,由 genre 和 sold 兩個屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
    chart.interval().position('genre*sold').color('genre')

    // Step 4: 渲染圖表
    chart.render()
  }

</script>

<template>
  <div class="demo">
    <div style="width: 100%; height: 300px">
      <canvas id="container" style="width: 100%; height: 100%"></canvas>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.demo {
  text-align: center;  
  .logo {
    height: 6em;
    padding: 1.5em;
    will-change: filter;
    transition: filter 300ms;
  }
  .logo:hover {
    filter: drop-shadow(0 0 2em #646cffaa);
  }
}
</style>
radar
<script setup lang="ts">
import { onMounted } from 'vue'

import F2 from '@antv/f2'
import _ from 'lodash'

const data = [
  {
    item: 'Design',
    user: '用戶 A',
    score: 70,
  },
  {
    item: 'Design',
    user: '用戶 B',
    score: 30,
  },
  {
    item: 'Development',
    user: '用戶 A',
    score: 60,
  },
  {
    item: 'Development',
    user: '用戶 B',
    score: 70,
  },
  {
    item: 'Marketing',
    user: '用戶 A',
    score: 50,
  },
  {
    item: 'Marketing',
    user: '用戶 B',
    score: 60,
  },
  {
    item: 'Users',
    user: '用戶 A',
    score: 40,
  },
  {
    item: 'Users',
    user: '用戶 B',
    score: 50,
  },
  {
    item: 'Test',
    user: '用戶 A',
    score: 60,
  },
  {
    item: 'Test',
    user: '用戶 B',
    score: 70,
  },
  {
    item: 'Language',
    user: '用戶 A',
    score: 70,
  },
  {
    item: 'Language',
    user: '用戶 B',
    score: 50,
  },
  {
    item: 'Technology',
    user: '用戶 A',
    score: 70,
  },
  {
    item: 'Technology',
    user: '用戶 B',
    score: 40,
  },
  {
    item: 'Support',
    user: '用戶 A',
    score: 60,
  },
  {
    item: 'Support',
    user: '用戶 B',
    score: 40,
  },
];

onMounted(() => {
  setTimeout(() => {
    drawChart();
  }, 1000);
});

function drawChart() {
  const chart: F2.Chart<F2.DataRecord> = (new F2.Chart({
    id: 'RadarChart',
    pixelRatio: window.devicePixelRatio,
  })) || null;

  chart.coord('polar');
  chart.source(data, {
    score: {
      min: 0,
      max: 120,
      nice: false,
      tickCount: 4,
    },
  });
  chart.axis('score', {
    label: function label(index, total) {
      if (index === total - 1) {
        return null;
      }
      return {
        top: true,
      };
    },
    grid: function grid(text) {
      if (text === '120') {
        return {
          lineDash: null,
        };
      }
    },
    line: {
      top: false,
    },
  });
  chart
    .area()
    .position('item*score')
    .color('user')
    .animate({
      appear: {
        animation: 'groupWaveIn',
      },
    });
  chart
    .line()
    .position('item*score')
    .color('user')
    .animate({
      appear: {
        animation: 'groupWaveIn',
      },
    });
  chart
    .point()
    .position('item*score')
    .color('user')
    .style({
      stroke: '#fff',
      lineWidth: 1,
    })
    .animate({
      appear: {
        delay: 300,
      },
    });

  chart.render();
}
</script>

<template>
  <div class="demo">
    <div style="width: 100%; height: 300px">
      <canvas id="RadarChart" style="width: 100%; height: 100%"></canvas>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.demo {
  text-align: center
}
</style>

PC端

antv

antv G6

快速上手 · 語雀

antv/g6是一款基于JavaScript圖形可視化引擎,由阿里巴巴的AntV團隊開發(fā)。

創(chuàng)建各種類型的圖形,如流程圖、關系圖、樹形圖等。

G6采用了自己的繪圖模型渲染引擎,使其具備高性能的圖形渲染能力。

它支持SVGCanvas兩種渲染方式,并且可以在Web移動端應用中使用。

Vue2

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

?注冊自定義節(jié)點、注冊行為

<template>
  <div class="custome-G6">
    <div :id="containerId"></div>
    <mds-modal class="custome-G6-modal" :visibility.sync="moreModal.visibility" title="選擇操作" width="300px" :mask="true"
      :footer="false" :showClose="true">
      <div class="more-content">
        <mds-button v-if="currentModel && currentModel.type !== 'node-root'" ghost type="primary"
          @click="editNode">修改指標名稱</mds-button>

        <mds-button v-if="currentModel && currentModel.indexFlag === 1" ghost type="primary"
          @click="addNode('sub')">添加下級指標</mds-button>
        <mds-button v-if="currentModel && currentModel.indexFlag === 1" ghost type="primary"
          @click="addNode('leaf')">添加底層指標</mds-button>
        <mds-button v-if="currentModel && currentModel.type !== 'node-root'" ghost type="danger"
          @click="handleDeleteNode">刪除指標</mds-button>
      </div>
    </mds-modal>

    <!-- 添加指標彈窗 -->
    <mds-modal class="custome-G6-modal" :visibility.sync="addModal.visibility" :title="addModal.title" width="300px"
      :mask="false" :showClose="true" okText="確定" @ok="handleAddNode" @close="handleClose">
      <div style="height: 100px">
        <template v-if="addModal.nodeType === 'leaf'">
          <mds-select v-model="addModal.leaf" value-key="id" placeholder="請選擇" filterable @change="changeLeaf">
            <mds-option v-for="item in quaryScoreIndexList" :key="item.id" :value="item"
              :label="item.indexNm"></mds-option>
          </mds-select>

          <div class="tip-text">請選擇1個底層指標</div>
        </template>
        <template v-else>
          <mds-input v-model="addModal.content.indexName" :maxlength="30"></mds-input>
          <div class="tip-text">請?zhí)顚懴录壷笜嗣Q,不超過30字</div>
        </template>
      </div>
    </mds-modal>

    <mds-modal class="custome-G6-modal" :visibility.sync="deleteModal.visibility" title="刪除指標提示" width="300px"
      :mask="false" :showClose="true" okText="確定" @ok="deleteNode" @close="closeDelete">
      <div style="height: 100px">
        <div>將刪除 “<span style="font-weight:bold">{{ currentModel && currentModel.indexName }}</span>”
          <template v-if="currentModel && currentModel.type === 'node-sub'">及其<span
              style="font-weight:bold">所有下級指標</span></template>
          ,確定嗎?
        </div>
      </div>
    </mds-modal>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch, Emit } from 'vue-property-decorator'
import G6 from '@antv/g6'

@Component({
  components: {}
})

export default class CustomeG6 extends Vue {
  @Prop({ required: true }) private containerId!: string
  @Prop({ required: true }) private indexContent!: any
  @Prop({ required: true }) private quaryScoreIndexList!: any
  @Prop({ required: true }) private disabled!: boolean

  // 更新根節(jié)點名稱
  @Watch('indexContent.indexName', { deep: true })
  changeIndexName(val: any, old: any) {
    // 獲取樹的根節(jié)點
    let rootNode = this.tree.getNodes()[0];
    // 更新根節(jié)點的索引名為新的值
    this.tree.updateItem(rootNode, { indexName: val });
    // 渲染更新后的樹
    this.tree.render();
  }

  private tree: any

  private moreModal: any = {
    visibility: false
  }

  private addModal: any = {
    visibility: false,
    title: '添加下級指標',
    leaf: '',
    content: {
      indexName: '',
      indexCode: null
    },
    nodeType: 'leaf',
    opType: 'add'
  }

  private deleteModal: any = {
    visibility: false,
  }

  currentEvt: any = null
  currentModel: any = null

  currentAction = ''

  // 關閉刪除指標彈窗
  closeDelete() {
    this.deleteModal.visibility = false
  }

  // 打開刪除指標彈窗
  handleDeleteNode() {
    this.deleteModal.visibility = true
  }
  // 確定刪除指標
  deleteNode() {
    const parent = this.currentEvt.item.get('parent');
    const model = this.currentEvt.item.get('model');

    this.currentEvt.currentTarget.updateItem(parent, {
      children: (parent.get('model').children || []).filter((e: any) => e.id !== model.id),
    });
    this.currentEvt.currentTarget.layout(false);

    this.closeDelete()
    this.moreModal.visibility = false
    this.$emit('update:indexContent', this.tree.get('data'))
  }

  // 修改指標名稱
  editNode() {
    const model = this.currentEvt.item.get('model');

    if (this.currentModel.type === 'node-leaf') {
      this.addModal.content.indexCode = model.indexCode
      this.addModal.leaf = {
        id: model.indexCode,
        indexNm: model.indexName
      }
    } else {
      this.addModal.content.indexCode = ''
    }

    this.addModal.nodeType = this.currentModel.type === 'node-leaf' ? 'leaf' : 'sub'
    this.addModal.content.indexName = model.indexName
    this.addModal.opType = 'edit'
    this.addModal.title = '修改指標名稱'
    this.addModal.visibility = true
  }

  // 關閉添加指標彈窗
  handleClose() {
    this.addModal.content.indexName = ''
    this.addModal.content.indexCode = ''
    this.addModal.visibility = false
    console.log('關閉添加指標彈窗')
  }

  addNode(type: string) {
    this.addModal.opType = 'add'
    this.addModal.nodeType = type
    this.addModal.title = `添加${type === 'leaf' ? '底層' : '下級'}指標`
    this.addModal.visibility = true
  }

  // 添加指標
  handleAddNode() {
    if (!this.addModal.content.indexName.trim()) {
      this.$message.error(this.addModal.nodeType === 'sub' ? '請輸入下級指標' : '請選擇底層指標')
      return
    }

    if (this.addModal.nodeType === 'sub') {
      this.addModal.content.indexCode = ''
    }
    const model = this.currentEvt.item.get('model');
    // console.log('點擊的name::::', name)
    const newId = model.id + '-' +
      (((model.children || []).reduce((a: any, b: any) => {
        const num = Number(b.id.split('-').pop());
        return a < num ? num : a;
      }, 0) || 0) +
        1);

    let obj
    if (this.addModal.opType === 'add') {
      obj = {
        children: (model.children || []).concat([{
          id: newId,
          direction: 'right',
          indexFlag: this.addModal.nodeType === 'sub' ? 1 : 2,
          indexCode: this.addModal.content.indexCode,
          indexName: this.addModal.content.indexName,
          children: [],
          type: this.addModal.nodeType === 'sub' ? 'node-sub' : 'node-leaf',
          color: '#aaa',
        },]),
      }
      console.log('添加指標:', this.addModal.nodeType, obj)

    } else {
      obj = {
        indexName: this.addModal.content.indexName,
        indexCode: this.addModal.content.indexCode
      }
    }

    this.currentEvt.currentTarget.updateItem(this.currentEvt.item, obj);
    this.currentEvt.currentTarget.layout(false);
    this.addModal.visibility = false
    this.addModal.content.indexName = ''
    this.addModal.content.indexCode = null
    this.addModal.leaf = ''
    this.moreModal.visibility = false

    this.$emit('update:indexContent', this.tree.get('data'))
  }

  // 選擇底層指標
  changeLeaf(val: any) {
    if (!val) {
      this.addModal.content.indexName = ''
      this.addModal.content.indexCode = ''
      return
    }
    this.addModal.content.indexName = val.indexNm
    this.addModal.content.indexCode = val.id
  }

  updateTree() {
    this.tree.data(this.indexContent)
    this.tree.render()
  }

  mounted() {
    const _this = this
    const { Util } = G6;


    // <text style={{ marginLeft: ${width - 16}, marginTop: -18, stroke: '', fill: '#000', fontSize: 16, cursor: 'pointer', opacity: ${cfg.hover ? 0.75 : 0} }} action="add">+</text>

    // <group zIndex=9999>
    //   <rect style={{ width: 100, height: 42, stroke: ${stroke}, fill: ${fill}, marginLeft: ${ width + 30 }, marginTop: -24, cursor: 'pointer', opacity: ${cfg.openMore ? 1 : 0} }} action="addSub">
    //     <Text style={{ marginLeft: ${ width + 42 }, marginTop: 12, cursor: 'pointer', opacity: ${cfg.openMore ? 1 : 0} }} action="addSub">添加下級指標</Text>
    //   </rect>
    //   <rect style={{ width: 100, height: 42, stroke: ${stroke}, fill: ${fill}, marginLeft: ${ width + 30 }, marginTop: -24, cursor: 'pointer', opacity: ${cfg.openMore ? 1 : 0} }} action="addLeaf">
    //     <Text style={{ marginLeft: ${ width + 42 }, marginTop: 12, cursor: 'pointer', opacity: ${cfg.openMore ? 1 : 0} }} action="addLeaf">添加底層指標</Text>
    //   </rect>
    // </group>

    // 根結點
    // 使用 G6.registerNode() 方法注冊一個名為 'node-root' 的自定義節(jié)點
    G6.registerNode(
      'node-root', // 節(jié)點名稱,這里為 'node-root'

      {
        // jsx 屬性指定節(jié)點的渲染函數(shù),用于生成節(jié)點的 HTML/SVG 內(nèi)容
        jsx: (cfg: any) => {
          // 計算節(jié)點內(nèi)容的寬度,以便在渲染時使用
          // 16: 文本字體大小 (font size)
          // 它表示文本的最大寬度。在這里傳遞 [0] 作為參數(shù),可能意味著測量文本的實際寬度,而不限制其最大寬度
          // 24: 這是在計算節(jié)點內(nèi)容寬度時額外添加的寬度值。在代碼中,它被用作一個修正項,可能是為了確保節(jié)點的寬度足夠容納文本內(nèi)容,并且在節(jié)點左右兩側留有一定的間隔
          const width = Util.getTextSize(cfg.indexName, 16)[0] + 24;

          // 獲取節(jié)點樣式中的邊框顏色,默認為 '#CED4E0'
          const stroke = cfg.style.stroke || '#CED4E0';

          // 獲取節(jié)點樣式中的填充顏色,默認為 '#FFF'
          const fill = cfg.style.fill || '#FFF';

          // 返回節(jié)點的 HTML/SVG 內(nèi)容
          return `
      <group>
        <rect draggable="true" style={{width: ${width}, height: 42, stroke: ${stroke}, fill: ${fill}, radius: 8 }} keyshape>
          <text style={{ fontSize: 16, marginLeft: 12, marginTop: 12 }}>${cfg.indexName}</text>
          <Circle style={{ r: 10, fill: '#FFF', stroke: ${stroke}, marginLeft: ${width + 14}, marginTop: 4 }}>
            <Text style={{ fill: ${_this.disabled ? '#ddd' : '#1564FF'}, fontSize: 18, lineHeight: 24, marginLeft: ${width + 7}, marginTop: -12, cursor: ${_this.disabled ? 'not-allowed' : 'pointer'} }} action="more">...</Text>
          </Circle>
        </rect>
      </group>
    `;
        },

        // getAnchorPoints() 方法定義節(jié)點的錨點位置,即連接邊的起始和結束點
        getAnchorPoints() {
          // 返回一個數(shù)組,數(shù)組中包含兩個錨點位置
          // 第一個錨點位于節(jié)點的左邊中點 [0, 0.5]
          // 第二個錨點位于節(jié)點的右邊中點 [1, 0.5]
          return [
            [0, 0.5],
            [1, 0.5],
          ];
        },
      },

      'single-node' // 節(jié)點類型,這里為 'single-node'
    );


    // 子節(jié)點
    // <text style={{ marginLeft: ${width - 32}, marginTop: -18, fill: '#000', fontSize: 16, cursor: 'pointer', opacity: ${cfg.hover ? 0.75 : 0} }} action="add">+</text>
    // <text style={{ marginLeft: ${width - 16}, marginTop: -34, fill: '#000', fontSize: 16, cursor: 'pointer', opacity: ${cfg.hover ? 0.75 : 0}, next: 'inline' }} action="delete">-</text>
    G6.registerNode(
      'node-sub', {
      jsx: (cfg: any) => {
        const width = Util.getTextSize(cfg.indexName, 14)[0] + 24;
        const stroke = cfg.style.stroke || '#CED4E0';
        const fill = cfg.style.fill || '#FFF';
        const color = '#f00';

        return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 42, stroke: ${stroke}, fill: ${fill}, radius: 8 }} keyshape>
              <text style={{ fontSize: 14, marginLeft: 12, marginTop: 12 }}>${cfg.indexName}</text>
              <Circle style={{ r: 10, fill: '#FFF', stroke: ${stroke}, marginLeft: ${width + 14}, marginTop: 4 }}>
                <Text style={{ fill: ${_this.disabled ? '#ddd' : '#1564FF'}, fontSize: 18, marginLeft: ${width + 7}, marginTop: -12, cursor: ${_this.disabled ? 'not-allowed' : 'pointer'}, }} action="more">...</Text>
              </Circle>
            </rect>
          </group>
          `;
      },
      getAnchorPoints() {
        return [
          [0, 0.5],
          [1, 0.5],
        ];
      },
    },
      'single-node',
    );

    // 葉子節(jié)點
    // <text style={{ marginLeft: ${width - 16}, marginTop: -18, stroke: ${color}, fill: '#000', cursor: 'pointer', opacity: ${cfg.hover ? 0.75 : 0}, next: 'inline' }} action="delete">-</text>
    G6.registerNode(
      'node-leaf', {
      jsx: (cfg: any) => {
        const width = Util.getTextSize(cfg.indexName, 14)[0] + 24;
        const stroke = cfg.style.stroke || '#CED4E0';
        const fill = cfg.style.fill || '#FFF';
        const color = cfg.color || cfg.style.stroke;

        return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 42, stroke: ${stroke}, fill: ${fill}, radius: 8}} keyshape>
              <text style={{ fontSize: 14, marginLeft: 12, marginTop: 12 }}>${cfg.indexName}</text>
              <Circle style={{ r: 10, fill: '#FFF', stroke: ${stroke}, marginLeft: ${width + 14}, marginTop: 4 }}>
                <Text style={{ fill: ${_this.disabled ? '#ddd' : '#1564FF'}, fontSize: 18, marginLeft: ${width + 7}, marginTop: -12, cursor: ${_this.disabled ? 'not-allowed' : 'pointer'}, }} action="more">...</Text>
              </Circle>
            </rect>
          </group>
          `;
      },
      getAnchorPoints() {
        return [
          [0, 0.5],
          [1, 0.5],
        ];
      },
    },
      'single-node',
    );

// 雙擊修改節(jié)點名稱
editNode(evt: any) {
  const item = evt.item;
  const model = item.get('model');
  // 根結點不能修改名稱
  if (model.type === 'node-root') return;

  console.log('model:::---:', model);

  // 獲取節(jié)點位置
  const { x, y } = item.calculateBBox();

  // 獲取圖表對象
  const graph = evt.currentTarget;

  // 將節(jié)點位置轉換為實際位置
  const realPosition = evt.currentTarget.getClientByPoint(x, y);

  // 創(chuàng)建一個文本輸入框
  const el = document.createElement('div');
  const fontSizeMap: any = {
    'node-root': 24,
    'node-sub': 18,
    'node-leaf': 18,
  };
  el.style.fontSize = fontSizeMap[model.type] + 'px';
  el.style.position = 'fixed';
  el.style.top = realPosition.y + 4 + 'px';
  el.style.left = realPosition.x + 'px';
  el.style.paddingLeft = '6px';
  el.style.transformOrigin = 'top left';
  el.style.transform = `scale(${evt.currentTarget.getZoom()})`;

  const input = document.createElement('input');
  input.style.border = 'none';
  input.value = model.indexName;
  input.style.width = Util.getTextSize(model.indexName, fontSizeMap[model.type])[0] + 'px';
  input.className = 'dice-input';
  el.className = 'dice-input';
  el.appendChild(input);
  document.body.appendChild(el);

  // 定義銷毀文本輸入框的函數(shù)
  const destroyEl = () => {
    document.body.removeChild(el);
  };

  // 定義處理點擊事件的函數(shù)
  const clickEvt = (event: any) => {
    if (!(event.target && event.target.className && event.target.className.includes('dice-input'))) {
      // 移除事件監(jiān)聽器
      window.removeEventListener('mousedown', clickEvt);
      window.removeEventListener('scroll', clickEvt);
      
      // 更新節(jié)點名稱并重新布局圖表
      graph.updateItem(item, {
        indexName: input.value,
      });
      graph.layout(false);
      
      // 移除滾輪縮放事件監(jiān)聽器,并銷毀文本輸入框
      graph.off('wheelZoom', clickEvt);
      destroyEl();
    }
  };

  // 添加事件監(jiān)聽器,處理點擊事件
  graph.on('wheelZoom', clickEvt);
  window.addEventListener('mousedown', clickEvt);
  window.addEventListener('scroll', clickEvt);

  // 監(jiān)聽輸入框的鍵盤事件,如果按下 Enter 鍵,觸發(fā)點擊事件
  input.addEventListener('keyup', (event) => {
    if (event.key === 'Enter') {
      clickEvt({
        target: {},
      });
    }
  });
},
 hoverNode(evt: any) {
        evt.currentTarget.updateItem(evt.item, {
          hover: true,
        });
      },

      hoverNodeOut(evt: any) {
        evt.currentTarget.updateItem(evt.item, {
          hover: false,
        });
      },
    });

?G6 圖形庫的行為(Behavior),用于在畫布上實現(xiàn)縮放和平移操作。當用戶在畫布上滾動鼠標滾輪時,會根據(jù)情況執(zhí)行縮放或平移操作。如果同時按下了 Ctrl 鍵,則進行縮放操作,否則進行平移操作。

// 在 G6 中注冊名為 'scroll-canvas' 的行為
G6.registerBehavior('scroll-canvas', {
  // 獲取事件列表
  getEvents: function getEvents() {
    return {
      wheel: 'onWheel', // 當滾輪滾動事件發(fā)生時,調(diào)用 onWheel 方法
    };
  },

  // 處理滾輪滾動事件的方法
  onWheel: function onWheel(ev: any) {
    const { graph } = _this; // 從 this 對象中獲取 graph,這里的 _this 表示當前行為實例
    if (!graph) {
      return;
    }
    if (ev.ctrlKey) { // 如果按下了 Ctrl 鍵
      const canvas = graph.get('canvas'); // 獲取畫布對象
      const point = canvas.getPointByClient(ev.clientX, ev.clientY); // 根據(jù)鼠標位置獲取畫布上的坐標點
      let ratio = graph.getZoom(); // 獲取當前圖形的縮放比例
      if (ev.wheelDelta > 0) { // 如果滾輪向上滾動
        ratio += ratio * 0.05; // 將縮放比例增加 5%
      } else {
        ratio *= ratio * 0.05; // 否則將縮放比例減少 5%
      }
      graph.zoomTo(ratio, {
        x: point.x, // 設置縮放中心點的 x 坐標
        y: point.y, // 設置縮放中心點的 y 坐標
      });
    } else {
      const x = ev.deltaX || ev.movementX; // 獲取水平方向上的滾動距離
      const y = ev.deltaY || ev.movementY || (-ev.wheelDelta * 125) / 3; // 獲取垂直方向上的滾動距離
      graph.translate(-x, -y); // 平移圖形,向相反方向移動
    }
    ev.preventDefault(); // 阻止默認滾動事件,避免影響整個頁面的滾動
  },
});
  • 節(jié)點被點擊時,觸發(fā)'node:click'事件,調(diào)用'clickNode'函數(shù)。
  • 節(jié)點被雙擊時,觸發(fā)'node:dblclick'事件,原本預計調(diào)用'editNode'函數(shù),但該函數(shù)體被注釋掉了。
  • 鼠標進入節(jié)點時,觸發(fā)'node:mouseenter'事件,調(diào)用'hoverNode'函數(shù)。
  • 鼠標離開節(jié)點時,觸發(fā)'node:mouseleave'事件,調(diào)用'hoverNodeOut'函數(shù)。
// 假設這是一個名為G6的圖形引擎,通過registerBehavior注冊了一個名為'dice-mindmap'的行為

G6.registerBehavior('dice-mindmap', {
  // 獲取事件列表的方法
  getEvents() {
    return {
      // 當節(jié)點被點擊時觸發(fā)'node:click'事件,調(diào)用'clickNode'方法
      'node:click': 'clickNode',
      // 當節(jié)點被雙擊時觸發(fā)'node:dblclick'事件,但該行為被注釋掉了,沒有調(diào)用對應的方法
      // 'node:dblclick': 'editNode',
      // 當鼠標進入節(jié)點時觸發(fā)'node:mouseenter'事件,調(diào)用'hoverNode'方法
      'node:mouseenter': 'hoverNode',
      // 當鼠標離開節(jié)點時觸發(fā)'node:mouseleave'事件,調(diào)用'hoverNodeOut'方法
      'node:mouseleave': 'hoverNodeOut',
    };
  },

  // 節(jié)點被點擊時調(diào)用的方法
  clickNode(evt: any) {
    // 獲取節(jié)點相關信息
    const model = evt.item.get('model');
    const name = evt.target.get('action');
    _this.currentAction = name; // 假設_this是之前定義過的變量,用于保存當前的動作名稱

    switch (name) {
      // case 'addSub':
      // case 'addLeaf':
      //   // 添加子節(jié)點或葉節(jié)點的邏輯代碼
      //   // ...
      //   break;

      // case 'delete':
      //   // 刪除節(jié)點的邏輯代碼
      //   // ...
      //   break;

      // case 'edit':
      //   // 編輯節(jié)點的邏輯代碼
      //   console.log('edit::::')
      //   break;

      case 'more':
        // 如果當前沒有被禁用
        if (!_this.disabled) {
          // 假設_this是之前定義過的變量,用于保存當前的事件和節(jié)點模型
          _this.currentEvt = evt;
          _this.currentModel = model;

          // 打印當前節(jié)點模型信息
          console.log('currentModel::::', _this.currentModel);

          // 假設_moreModal是之前定義過的變量,用于顯示更多操作的彈窗
          _this.moreModal.visibility = true;

          // 可以根據(jù)需要執(zhí)行其他操作
          // ...
        }
        break;

      default:
        // 如果沒有匹配到任何動作名稱,直接返回
        return;
    }

    // 可以在這里添加其他代碼邏輯
    // ...
  },

  // 其他方法
  // ...
});

將輸入的數(shù)據(jù)對象進行轉換,并根據(jù)不同層級進行相應的屬性設置。在轉換過程中,會對節(jié)點的類型、懸停狀態(tài)、展開狀態(tài)等進行處理,同時為部分節(jié)點設置默認值。如果節(jié)點包含子節(jié)點,會遞歸地處理子節(jié)點的數(shù)據(jù)。

// 定義數(shù)據(jù)轉換函數(shù) dataTransform,接收一個參數(shù) data,該參數(shù)為任意類型的數(shù)據(jù)
const dataTransform = (data: any) => {
  // 定義內(nèi)部遞歸函數(shù) changeData,接收兩個參數(shù):d 表示當前數(shù)據(jù)節(jié)點,level 表示當前數(shù)據(jù)節(jié)點的層級,默認值為 0
  const changeData: any = (d: any, level = 0) => {
    // 創(chuàng)建一個新的數(shù)據(jù)對象 data,用擴展運算符復制當前數(shù)據(jù)節(jié)點 d 的所有屬性到新對象中
    const data = {
      ...d,
    };
    // 使用 switch 語句根據(jù)當前節(jié)點層級 level 進行不同的處理
    switch (level) {
      case 0:
        // 當層級為 0 時,設置節(jié)點的 type 屬性為 'node-root'
        data.type = 'node-root';
        break;
      // case 1:
      //   data.type = 'node-sub';
      //   break;
      default:
        // 默認情況下,設置節(jié)點的 type 屬性為 'node-sub'
        data.type = 'node-sub';
        break;
    }

    // 設置節(jié)點的 hover 屬性為 false,表示鼠標未懸停在節(jié)點上
    data.hover = false;
    // 設置節(jié)點的 openMore 屬性為 false,表示未展開更多選項
    data.openMore = false;

    // 當節(jié)點層級為 1 且沒有 direction 屬性時,進行下面的處理
    if (level === 1 && !d.direction) {
      // 如果節(jié)點沒有 direction 屬性,則設置 direction 屬性為 'right'
      data.direction = 'right';
    }

    // 如果當前節(jié)點存在子節(jié)點,則遞歸處理每個子節(jié)點,并將返回的新數(shù)據(jù)添加到當前節(jié)點的 children 屬性中
    if (d.children) {
      data.children = d.children.map((child: any) => changeData(child, level + 1));
    }

    // 返回處理后的新數(shù)據(jù)對象
    return data;
  };

  // 調(diào)用遞歸函數(shù) changeData,并傳入初始的 data 參數(shù)進行數(shù)據(jù)轉換
  return changeData(data);
};
 const container: any = document.getElementById(_this.containerId);
    // const el = document.createElement('pre');
    // el.innerHTML = '雙擊修改節(jié)點標題';
    // container.appendChild(el);

    const width = container.scrollWidth;
    // const height = (container.scrollHeight || 500) - 20;
    this.tree = new G6.TreeGraph({
      container: _this.containerId,
      width: width,
      height: 300,
      fitView: true,
      fitViewPadding: [10, 20],
      layout: {
        type: 'mindmap',
        direction: 'H',
        nodesep: 80, // 可選
        ranksep: 40, // 可選
        // 節(jié)點高度
        getHeight: () => {
          return 16;
        },
        // 節(jié)點寬度
        getWidth: (node: any) => {
          return node.level === 0 ?
            Util.getTextSize(node.indexName, 16)[0] + 12 :
            Util.getTextSize(node.indexName, 12)[0];
        },
        // 節(jié)點之間的垂直間距
        getVGap: () => {
          return 40;
        },
        // 節(jié)點之間的水平間距
        getHGap: () => {
          return 84;
        },
        getSide: (node: any) => {
          return node.data.direction;
        },
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          lineWidth: 2,
        },
      },
      minZoom: 0.8,
      maxZoom: 1.5,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', 'dice-mindmap'],
      },
    });

    const data = dataTransform(_this.indexContent)
    this.$emit('update:indexContent', data)
    this.tree.data(data);

    this.tree.render();

    if (typeof window !== 'undefined') {
      window.onresize = () => {
        if (!this.tree || this.tree.get('destroyed')) return;
        if (!container || !container.scrollWidth || !container.scrollHeight) return;
        this.tree.changeSize(container.scrollWidth, 300);
      };
    }
scss
<style lang="scss">
.custome-G6-modal {
  .mds-modal {
    min-width: initial;
  }

  .more-content {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);
    column-gap: 12px;
    row-gap: 12px;
    padding-bottom: 48px;

    .mds-btn {
      width: auto;
      margin: 0;
    }
  }

  .mds-modal-header,
  .mds-modal-bottom {
    border: none;
  }

  .mds-modal-footer-default {
    justify-content: flex-end;

    button {
      flex: initial;
      width: 80px;
    }

    .mds-modal-button {
      margin-right: 2px;
    }
  }

  .tip-text {
    font-size: 12px;
    line-height: 18px;
    color: rgba(168, 172, 179, 1);
    margin-top: 10px;
  }
}
</style>

<style lang="scss" scoped>
.custome-G6 {
  background-color: #F9F9F9;
}
</style>

Echarts

Echarts是由百度開發(fā)的,更符合國人的習慣,支持各種類型的圖表,并具有良好的交互性能,文檔詳盡,友好,強烈推薦

缺點

  • 初學者可能會發(fā)現(xiàn)Echarts較難配置,需要額外的學習成本。

  • Echarts的可定制性可能會導致代碼變得冗長,增加了工作量和開發(fā)時間。

  • 在某些情況下,Echarts在渲染大型數(shù)據(jù)集時可能會變慢,這需要進行其他優(yōu)化才能提高性能。

  • npm uninstall echarts

    npm install echarts

    yarn remove echarts

    yarn add echarts

Vue3
radar
<template>
  <div>
    <div id="main" style="width: 100%; height: 300px;"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue';
import * as echarts from 'echarts/core';
import {
  TitleComponent,
  LegendComponent,
} from 'echarts/components';
import { RadarChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';

const { use } = echarts;
use([TitleComponent, LegendComponent, RadarChart, CanvasRenderer]);

const option = {

  legend: {
    bottom: 0, // 設置圖例在底部
    icon: 'circle', // 使用圓形圖例項的圖標
    data: ['能力模型', '我的評分']
  },
  radar: {
    //逆時針
    indicator: [
      { name: '學習能力及影響力', max: 8 },
      { name: '溝通能力', max: 8 },
      { name: '目標管理', max: 8 },
      { name: '項目執(zhí)行', max: 8 },
      { name: '專業(yè)能力', max: 8 }
    ]
  },
  series: [
    {
      name: '能力模型 vs 我的評分',
      type: 'radar',
      data: [
        {
          value: [6, 6, 6, 4, 8],
          name: '能力模型',
          lineStyle: {
            color: '#3F80F2' // 將顏色設置為藍色
          },
          itemStyle: {
            color: '#3F80F2' // 將數(shù)據(jù)點顏色設置為藍色
          },

          areaStyle: {
            color: new echarts.graphic.RadialGradient(0.1, 0.6, 1, [
              {
                color: 'rgba(63, 128, 242, 0.1)',
                offset: 0
              },
              {
                color: 'rgba(63, 128, 242, 0.9)',
                offset: 1
              }
            ])
          }
        },
        {
          value: [8, 5, 4, 6, 8],
          name: '我的評分',
          lineStyle: {
            color: '#EB532E' // 將顏色設置為紅色
          },
          itemStyle: {
            color: '#EB532E' // 將數(shù)據(jù)點顏色設置為紅色
          },
          areaStyle: {
            color: new echarts.graphic.RadialGradient(0.1, 0.6, 1, [
              {
                color: 'rgba(255, 145, 124, 0.1)',
                offset: 0
              },
              {
                color: 'rgba(255, 145, 124, 0.9)',
                offset: 1
              }
            ])
          }
        }
      ]
    }
  ]
};

onMounted(() => {
  const chartDom = document.getElementById('main');
  if (chartDom) {
    const myChart = echarts.init(chartDom);
    myChart.setOption(option);
  }
});
</script>

<style>
/* 根據(jù)需要添加樣式 */
</style>

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript?

React
原生echarts+TS

原生echats官方文檔和功能比echarts-for-react全,

但echarts-for-react對react支持更友好,使用更簡單???????

ListChart(列表切換echarts圖表,同類數(shù)據(jù)為x軸的bar)

移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

?移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】,前端面試,開發(fā),React和Vue,vue.js,前端,javascript

ListChart.tsx
import React, { useEffect, useRef, useState } from 'react';
import { List, Button} from 'antd';
import { LineChartOutlined, BarChartOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import * as echarts from "echarts";

import './ListChart.css'
import { LIST_NAME, CHART_OPTION,resize,findSubstrIdx } from '../utils/ListChartUtil';
import { ListChartStatus } from "./ListChartStatus";

const ListChart: React.FC<ListChartStatus> = ({ urlPre, proc_datas, board_name }) => {

    const chartRef = useRef<HTMLDivElement>(null); 
    const [selectedIdx, setselectedIdx] = useState<number>(0);
    const [isLine, setIsLine] = React.useState<boolean>(true);
    const proc_list = new Array(proc_datas.length).fill(null).map((val, i) => {
        return proc_datas[i].proc_name;
    });
    let chart: any = null;
    
    useEffect(() => {
        if (chartRef.current) {
            chart = echarts.init(chartRef.current);
            const {option,urlSufs}=getOption(proc_datas[selectedIdx])
            chart.setOption(option);
            resize(chart);
            chart.on('click', isLine ? 'xAxis' : 'series', function (params: any) {
                const clickDate= isLine ? params.value:params.seriesName;
                window.open(urlPre + '/' + urlSufs[findSubstrIdx(urlSufs, clickDate)] + '/index.html', '_blank');
            });
        }  
    }, [chartRef, selectedIdx, isLine]);

    const initDate_UrlSufs=(proc_data:any)=>{
        let urlSufs: string[] = [];
        let dates: string[] = [];
        proc_data.date_list.forEach((date: string, idx: number) => {
            urlSufs.push(date + '/' + proc_data.report_id_list[idx]);
            dates.push(date.substring(5));
        });
        return {dates,urlSufs};
    }
    const  getBarDates=(series:any)=>{
        const barDatas: any = [];
        LIST_NAME.forEach((_, idx) => {
            if (series[idx] && series[idx].length) {
                barDatas.push([LIST_NAME[idx], ...series[idx]])
            }
        })
        return barDatas;
    }
    const getOption=(proc_data:any)=>{
        const {dates,urlSufs}=initDate_UrlSufs(proc_data)
        const series = [proc_data.avg_list, proc_data.sigma3_up_list, proc_data.sigma3_up_target_list, proc_data.sigma3_down_list, proc_data.max_list, proc_data.min_list]
        let option = {  
            tooltip: CHART_OPTION.tooltip,
            legend: CHART_OPTION.legend,
            toolbox: CHART_OPTION.toolbox,
            yAxis: CHART_OPTION.yAxis,
            title: {
                text: proc_data ? board_name + ":" + proc_data.proc_name : board_name,
                subtext: "點擊日期可跳轉到詳情報告",
            },
            xAxis: {
                type: 'category', // 類型為分類軸
                triggerEvent: true, // 是否觸發(fā)鼠標事件
                data: isLine ? proc_data.date_list.map((date: string, idx: number) => {
                    return dates[idx]
                }) : null,
            },
            series: isLine ? LIST_NAME.map((_, idx) => {
                if (series[idx] && series[idx].length) {
                    return {
                        name: LIST_NAME[idx],
                        type: 'line',
                        data: series[idx],
                        emphasis: {
                            focus: 'series'
                        },
                    }
                }
            }) : dates.map((_, idx) => {
                return {
                    name: dates[idx],
                    type: 'bar',
                    event: 'click',
                    emphasis: {
                        focus: 'series'
                    },
                }
            }),

            dataset: isLine ? null : {
                source: [
                    ['pref', ...dates],
                    ...getBarDates(series)
                ]
            },
        };
        return {option,urlSufs};
    }
    return (<ProCard layout="center"  className="procard" ghost>
        <ProCard colSpan={6} ghost >
            <List
                size="small"
                bordered
                className='procard-list'
                dataSource={proc_list}
                renderItem={(item, index) => <List.Item key={Math.random()} className={selectedIdx === index ? 'selected' :undefined }
                    onClick={() => setselectedIdx(index)}>
                    {item}</List.Item>}
            />
        </ProCard>
        <ProCard colSpan={18} ghost >
            <div className="procard-button" >
                <Button className="ant-btn" icon={<LineChartOutlined />} onClick={() => setIsLine(true)} ></Button>
                <Button className="ant-btn" icon={<BarChartOutlined />} onClick={() => setIsLine(false)}></Button>
            </div>
            <div key={`divChart${Math.random()}`}
                ref={chartRef}
                className='chart'
                style={{
                    flex: 2,
                    flexDirection:"column",
                    height: "40vh",
                    paddingLeft: "1vw",
                }}
            ></div>
        </ProCard>
    </ProCard>
    )
}
export default ListChart;
ListChart.css
.procard {
    display: flex;
    padding-top: 10px;
}
.procard-list {
    overflow-y: scroll;
    height: 45vh;
}
.selected {
    background-color: #e6f7ff !important;
  }
.procard-button{
    display: flex;
    justify-content: flex-end;
    padding-right: 7vw;
}
ListChartUtil.tsx
?
export const LIST_NAME = ['avg', '3∑-up', '3∑-up-target', '3∑-down', 'max', 'min']

export const CHART_OPTION = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: "shadow"
    },
  },
  legend: {
    left: 'center',
    width: '35%',
    selected: {
      'min': false,
      '3∑-down': false,
    }
  },
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: { readOnly: false },
      //   magicType: { type: ['line'] },
      restore: {},
      saveAsImage: {}
    },
    right: "10%"
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value}  '
    }
  },
}
const dom: any = [];  //所有echarts圖表的數(shù)組
/**
 * 當屏幕尺寸變化時,循環(huán)數(shù)組里的每一項調(diào)用resize方法來實現(xiàn)自適應。
 * @param {*} eDom 
 */
export function resize(eDom: any) {
  dom.push(eDom);
  window.onresize = () => {
    dom.forEach((it: any) => {
      it.resize();
    })
  };
}

export function findSubstrIdx(arr: string[], substr: string): number {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].indexOf(substr) !== -1) {
      return i;
    }
  }
  return -1;
}

?

?React hooks 封裝 ECharts5 通用組件 - 掘金

React+TypeScript封裝ECharts_typescript+react 封裝調(diào)用方法_KzXuanCn的博客-CSDN博客???????

GitHub - hustcc/echarts-for-react: ?? Apache ECharts components for React wrapper. 一個簡單的 Apache echarts 的 React 封裝。

Recharts???????

是一個基于React封裝的庫,使用了D3強大的繪圖功能,使得使用React進行數(shù)據(jù)可視化變得更加簡單。

優(yōu)點

  • Recharts易于使用,因為它具有數(shù)量較少的自定義選項。

  • 集成了React的生命周期方法,使它易于添加到React應用程序中,并可支持Redux狀態(tài)管理器。

  • 輕量級,對內(nèi)存和CPU的影響較小。

  • 支持多種樣式、自定義顏色和動畫。

缺點

  • 不支持所有類型的圖表,沒有Echarts種類繁多。

  • 功能相比于Echarts較少

綜上所述,如果需要設計高度自定義的圖表并且有足夠的開發(fā)經(jīng)驗,那么使用Echarts可能更方便。另一方面,Recharts對于快速簡單的數(shù)據(jù)可視化任務可能更適合,并且易于集成到React應用程序中。

D3

是一個基于數(shù)據(jù)驅動文檔的JavaScript庫,具有高度靈活性和自定義性,但需要更多的編碼工作。文章來源地址http://www.zghlxwxcb.cn/news/detail-667605.html

到了這里,關于移動端和PC端對比【組件庫+調(diào)試vconsole +構建vite/webpack+可視化echarts/antv】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • H5移動端調(diào)試方案全解(iOS&Android&Chrome&vConsole)

    H5移動端調(diào)試方案全解(iOS&Android&Chrome&vConsole)

    在移動端盛行的今天,大家在日常中經(jīng)常會接觸到H5的移動端網(wǎng)頁,不僅僅是在瀏覽器中,在各種的APP中也有存在著許多的H5頁面,所以我們作為前端開發(fā)者就會有在開發(fā)時候進行移動端調(diào)試、甚至是真機調(diào)試的需求,本文旨在一文帶領大家了解iOS、Android等平臺的調(diào)試以及模

    2024年02月05日
    瀏覽(20)
  • 前端移動端布局自適應 及移動端和PC端共用一套代碼注意事項

    前端移動端布局自適應 及移動端和PC端共用一套代碼注意事項

    前端移動端布局自適應 目錄 一、自適應布局概念? 二、使用步驟 1. head標簽里要寫適用移動端 2. 自適應單位問題 3. CSS如何寫? 總結 前言 移動端布局需要適應不同大小手機平板屏幕,所以字體圖片等尺寸就要做到隨著屏幕大小的變化去自適應,這樣會給用戶很好的體驗感和

    2024年02月08日
    瀏覽(29)
  • uni-app 可視化創(chuàng)建的項目 移動端安裝調(diào)試插件vconsole

    uni-app 可視化創(chuàng)建的項目 移動端安裝調(diào)試插件vconsole

    ?可視化創(chuàng)建的項目,在插件市場找不到vconsole插件了。 又不好npm?install vconsole 換個思路,先創(chuàng)建一個cli腳手架腳手架的uni-app項目,然后再此項目上安裝vconsole cli腳手架創(chuàng)建uni-app項目?安裝插件 項目Terminal運行命令:npm install vconsole ? 安裝完成之后,插件在node_modules/vconsol

    2024年02月10日
    瀏覽(23)
  • 構建工具 Vite、Webpack、Rollup對比

    構建工具 Vite、Webpack、Rollup對比

    熱更新方面:webpack支持HMR,但是webpack需要全部重新編譯并更新,效率較低 tree-shaking:webpack2開始支持且消除效果不好,但是webpack5有更好的tree-shaking(去除未使用代碼) 分包方面:webpack支持代碼切割。(分包) ESM打包:現(xiàn)在webpack支持es6module輸出 優(yōu)點: Rollup 是一款 ES Mod

    2024年02月09日
    瀏覽(23)
  • 前端構建工具對比 webpack、vite、esbuild等

    人類和動物最大的區(qū)別是會使用工具,工具的作用就是提升我們的生產(chǎn)效率,同樣,隨著前端工程化的演進,伴隨著一些優(yōu)秀的工程化的生產(chǎn)效率工具,今天就來聊一聊,前端工程中的構建工具。 前端構建工具按照功能可以分為如下兩大類: 轉譯 - 將高級語法轉換為低級的

    2024年01月19日
    瀏覽(48)
  • Charles:移動端抓包 / windows客戶端 / iOS手機 / HarmonyOS 4.0 / 手機訪問PC本地項目做調(diào)試

    Charles:移動端抓包 / windows客戶端 / iOS手機 / HarmonyOS 4.0 / 手機訪問PC本地項目做調(diào)試

    一、背景描述 1.1、本文需求:移動端進行抓包調(diào)試 1.2、理解Charles可以做什么 Charles是一款跨平臺的網(wǎng)絡代理軟件,可以用于捕獲和分析網(wǎng)絡流量,對HTTP、HTTPS、HTTP/2等協(xié)議進行調(diào)試和監(jiān)控。使用Charles可以幫助開發(fā)人員進行Web開發(fā)、調(diào)試和測試,同時也可以用于網(wǎng)絡安全和隱

    2024年02月08日
    瀏覽(25)
  • vue 拖動、縮放容器組件,支持移動端雙指縮放和PC端鼠標滾輪縮放

    本組件基于CSS的transform實現(xiàn)。移動端監(jiān)聽touch事件(單指移動,雙指移動+縮放),PC端監(jiān)聽mouse事件(移動)和滾動事件wheel(縮放),更新transform的translateX/translateY/scale值,從而實現(xiàn)縮放、移動。由于transform不會產(chǎn)生重排,因此不節(jié)流也可以有很好的性能,用戶體驗就像德芙

    2024年02月03日
    瀏覽(94)
  • 神器vConsole!快速定位移動端問題,加快開發(fā)效率

    大家好,我是程序視點的小二哥! 今天小二哥碰到一新來的實習生在使用 alert 調(diào)試H5頁面,仿佛看到小二哥年少時羞澀的樣子... 趁這個機會,就給大家分享一個針對手機網(wǎng)頁的前端開發(fā)者調(diào)試面板工具: vConsole vConsole 是框架無關的,可以在 Vue 、 React 或其他任何框架中使用。

    2024年02月07日
    瀏覽(21)
  • 前端必須知道的手機調(diào)試工具vConsole

    前端必須知道的手機調(diào)試工具vConsole

    在日常業(yè)務中我相信大家多多少少都有移動端的項目,移動端的項目需要真機調(diào)試的很多東西看不到調(diào)試起來也比較麻煩,今天給大家分享一個我認為比較好用的調(diào)試第三方庫 VConsole ,有了這個庫咱們就在手機上看控制臺了, VConsole有兩種引用方式,使用方法也很簡單 方法一

    2024年02月12日
    瀏覽(17)
  • Vue常用的組件庫大全【前端工程師必備】【移動端、PC端(web端)、數(shù)據(jù)可視化組件庫(數(shù)據(jù)大屏) 、動畫組件庫、3D組件庫】

    Vue常用的組件庫大全【前端工程師必備】【移動端、PC端(web端)、數(shù)據(jù)可視化組件庫(數(shù)據(jù)大屏) 、動畫組件庫、3D組件庫】

    1)Vant ui ??有贊移動 UI 組件庫,支持 Vue2/3 微信小程序,支付寶小程序 https://vant-contrib.gitee.io/vant/v2/#/zh-CN/col Vant 是由有贊前端團隊開發(fā)的一套基于 Vue.js 的移動端 UI 組件庫,它包含了豐富的組件和功能,可以幫助開發(fā)者快速構建高質(zhì)量的移動應用。Vant 以簡潔易用和高質(zhì)量

    2024年02月04日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包