欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue+openlayers+nodejs+postgis實現(xiàn)軌跡運動效果

 更新時間:2024年05月31日 10:29:58   作者:小白舒_SC  
使用postgres(postgis)數(shù)據(jù)庫以及nodejs作為后臺,vue和openlayers做前端,openlayers使用http請求通過nodejs從postgres數(shù)據(jù)庫獲取數(shù)據(jù),這篇文章主要介紹了vue+openlayers+nodejs+postgis實現(xiàn)軌跡運動,需要的朋友可以參考下

概要

使用openlayers實現(xiàn)軌跡運動

整體架構(gòu)流程

使用postgres(postgis)數(shù)據(jù)庫以及nodejs作為后臺,vue和openlayers做前端,openlayers使用http請求通過nodejs從postgres數(shù)據(jù)庫獲取數(shù)據(jù)。

技術(shù)名詞解釋

postgis:postgis是postgres的一個擴(kuò)展,提供空間對象的相關(guān)操作。

技術(shù)細(xì)節(jié)

nodejs直連數(shù)據(jù)庫,openlayers使用http服務(wù)通過nodejs轉(zhuǎn)為數(shù)據(jù)庫的查詢語句。

實現(xiàn)思路如下:每條數(shù)據(jù)表示一條船,每個船的軌跡關(guān)鍵點在數(shù)據(jù)庫存為MultiPointM的Geometry數(shù)據(jù),其中M分量為時間戳,然后前端傳入一個空間范圍和時間戳,空間范圍主要為了過濾范圍外要素加速渲染,時間戳則用來查詢所有船的軌跡點小于該時間戳的所有關(guān)鍵點,將其連成線,然后在時間戳所在的區(qū)間,使用線性插值插值出小船當(dāng)前位置,線和插值出的點有相同的fid,在前端通過fid將線和插值點連接并顯示,就是船的實時軌跡。

效果如下:

前端代碼如下:

<template>
  <div id="map" class="map"></div>
</template>
<script>
import * as ol from 'ol';
import 'ol/ol.css';
import proj from 'ol/proj'
import { fromLonLat } from 'ol/proj';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
import WKB from 'ol/format/WKB';
import Icon from 'ol/style/Icon';
import { transformExtent } from 'ol/proj';
export default {
  name: 'OpenLayersMap',
  data() {
    return {
      map: null,
      pointLayer: null,
      lineLayer: null,
      linesData: [],
      pointsData: [],
      iconImagePath: '../../board.png',
      lastPoint: {}
    };
  },
  mounted() {
    this.initializeMap();
    this.timeRange();
  },
  methods: {
    initializeMap() {
      this.map = new Map({
        target: 'map',
        layers: [
          new TileLayer({
            source: new XYZ({
              url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
            }),
          }),
        ],
        view: new View({
          center: [0, 0],
          zoom: 2,
        }),
      });
      this.lineLayer = new VectorLayer({
        source: new VectorSource(),
      });
      this.map.addLayer(this.lineLayer);
      this.pointLayer = new VectorLayer({
        source: new VectorSource(),
        style: new Style({
          image: new CircleStyle({
            radius: 6,
            fill: new Fill({ color: 'red' }),
            stroke: new Stroke({ color: 'white', width: 2 }),
          }),
        }),
      });
      this.map.addLayer(this.pointLayer);
    },
    timeRange() {
      fetch('http://localhost:4325/time-range')
        .then(response => response.json())
        .then(data => {
          const { minTime, maxTime } = data;
          console.log('Time Range:', minTime, maxTime);
          this.fetchDataInRange(minTime, maxTime);
        })
        .catch(error => console.error('Error fetching time range:', error));
    },
    fetchDataInRange(startTime, endTime) {
      let currentTime = startTime;
      const timerId = setInterval(() => {
        if (currentTime >= endTime) {
          this.fetchData(endTime);
          clearInterval(timerId); // Stop the timer when currentTime >= endTime
          return;
        }
        this.fetchData(currentTime);
        currentTime += 5; // Increment currentTime
        //console.log('Current Time:', currentTime);
      }, 200);
    },
    fetchData(currentTime) {
      // 獲取地圖視圖
      const mapView = this.map.getView();
      // 獲取地圖視圖的范圍
      const extent = mapView.calculateExtent(this.map.getSize());
      // 將范圍轉(zhuǎn)換為EPSG:4326坐標(biāo)系下的值 
      const bbox = transformExtent(extent, mapView.getProjection(), 'EPSG:4326');
      Promise.all([
        fetch(`http://localhost:4325/line-geometries?timestamp=${currentTime}&bbox=${bbox.join(',')}`).then(response => response.json()),
        fetch(`http://localhost:4325/points?timestamp=${currentTime}&bbox=${bbox.join(',')}`).then(response => response.json())
      ]).then(([linesData, pointsData]) => {
        this.linesData = linesData;
        this.pointsData = pointsData;
        this.processData();
      }).catch(error => console.error('Error fetching data:', error));
    },
    processData() {
      const lineSource = this.lineLayer.getSource();
      const pointSource = this.pointLayer.getSource();
      const existingLineFeatureIds = {};
      const existingPointFeatureIds = {};
      // 處理線要素數(shù)據(jù)
      //console.log('this.linesData', this.linesData)
      this.linesData.forEach(line => {
        const fid = line.fid;
        let feature = lineSource.getFeatureById(fid);
        if (feature) {
          // 如果已存在具有相同 fid 的要素,則更新要素信息
          // 更新要素信息
          existingLineFeatureIds[fid] = true;
        } else {
          // 否則創(chuàng)建新的要素并添加到圖層中
          feature = new Feature({
            // 設(shè)置要素信息
          });
          lineSource.addFeature(feature);
          existingLineFeatureIds[fid] = true;
        }
      });
      // 處理點要素數(shù)據(jù)
      this.pointsData.forEach(point => {
        const fid = point.fid;
        let feature = pointSource.getFeatureById(fid);
        if (feature) {
          // 如果已存在具有相同 fid 的要素,則更新要素信息
          // 更新要素信息
          existingPointFeatureIds[fid] = true;
        } else {
          // 否則創(chuàng)建新的要素并添加到圖層中
          feature = new Feature({
            // 設(shè)置要素信息
          });
          pointSource.addFeature(feature);
          existingPointFeatureIds[fid] = true;
        }
      });
      // 移除地圖上已存在但未在當(dāng)前數(shù)據(jù)中出現(xiàn)的線要素
      lineSource.getFeatures().forEach(feature => {
        const fid = feature.getId();
        if (!existingLineFeatureIds[fid]) {
          lineSource.removeFeature(feature);
        }
      });
      // 移除地圖上已存在但未在當(dāng)前數(shù)據(jù)中出現(xiàn)的點要素
      pointSource.getFeatures().forEach(feature => {
        const fid = feature.getId();
        if (!existingPointFeatureIds[fid]) {
          pointSource.removeFeature(feature);
        }
      });
      // Create a mapping of fid to points
      const pointsMap = {};
      this.pointsData.forEach(point => {
        if (!pointsMap[point.fid]) {
          pointsMap[point.fid] = [];
        }
        pointsMap[point.fid].push(point);
      });
      // Process lines and append points if they exist
      this.linesData.forEach(line => {
        const format = new WKB();
        const feature = format.readFeature(line.line_geom, {
          dataProjection: 'EPSG:4326',
          featureProjection: 'EPSG:3857'
        });
        const geometry = feature.getGeometry();
        if (geometry.getType() === 'LineString' && pointsMap[line.fid]) {
          const coordinates = geometry.getCoordinates();
          pointsMap[line.fid].forEach(point => {
            const coord = fromLonLat([point.interpolated_longitude, point.interpolated_latitude]);
            coordinates.push(coord);
          });
          geometry.setCoordinates(coordinates);
        }
        //feature.setId(line.fid);
        this.lineLayer.getSource().addFeature(feature);
      });
      // Log for debugging
      //console.log('Processed Lines:', this.lineLayer.getSource().getFeatures());
      //console.log('Processed Points:', this.pointLayer.getSource().getFeatures());
      this.processPointLayer();
    },
    processPointLayer() {
      const tempLastPoint = {};
      const lineFeatures = this.lineLayer.getSource().getFeatures();
      lineFeatures.forEach(lineFeature => {
        const lineGeometry = lineFeature.getGeometry();
        const lineCoordinates = lineGeometry.getCoordinates();
        const numCoordinates = lineCoordinates.length;
        //const fid = lineFeature.getId();
        //console.log('fid', fid);
        if (numCoordinates === 1) {
          const defaultAngle = 0;
          const lastPointCoords = lineCoordinates[0];
          tempLastPoint[fid] = lastPointCoords;
          const pointFeature = new Feature({
            geometry: new Point(lineCoordinates[0]),
          });
          //pointFeature.setId(fid);
          const iconStyle = this.createPointStyle(defaultAngle);
          pointFeature.setStyle(iconStyle);
          this.pointLayer.getSource().addFeature(pointFeature);
        } else if (numCoordinates > 1) {
          const lastPointCoords = lineCoordinates[numCoordinates - 1];
          //console.log('lastPointCoords', lastPointCoords);
          const penultimatePointCoords = lineCoordinates[numCoordinates - 2];
          const dx = lastPointCoords[0] - penultimatePointCoords[0];
          const dy = lastPointCoords[1] - penultimatePointCoords[1];
          const angle = Math.atan2(dy, dx);
          const pointFeature = new Feature({
            geometry: new Point(lastPointCoords),
          });
          //pointFeature.setId(fid);
          const iconStyle = this.createPointStyle(angle);
          pointFeature.setStyle(iconStyle);
          this.pointLayer.getSource().addFeature(pointFeature);
          //const tempLastPointCoords = this.lastPoint[fid];
          //console.log('tempLastPointCoords', tempLastPointCoords);
          //if (tempLastPointCoords) {
            //console.log('animate point', lineFeature.getId(), this.lastPoint[lineFeature.getId()], lastPointCoords);
            //this.animatePoint(pointFeature, tempLastPointCoords, lastPointCoords);
          //}
          //tempLastPoint[fid] = lastPointCoords;
        }
      });
      //this.lastPoint = tempLastPoint;
      //console.log('lastPoint', this.lastPoint); 
      //console.log('tempLastPoint', tempLastPoint);
    },
    animatePoint(feature, startCoords, endCoords) {
      const duration = 800; // 動畫持續(xù)時間,單位毫秒
      const start = performance.now();
    //console.log('startCoords', startCoords);
      const animate = (timestamp) => {
        const elapsed = timestamp - start;
        const progress = Math.min(elapsed / duration, 1); // 進(jìn)度百分比,范圍從0到1
        // 線性插值計算當(dāng)前位置
        const currentCoords = [
          startCoords[0] + (endCoords[0] - startCoords[0]) * progress,
          startCoords[1] + (endCoords[1] - startCoords[1]) * progress,
        ];
        feature.setGeometry(new Point(currentCoords));
        if (progress < 1) {
          requestAnimationFrame(animate);
        }
      };
      requestAnimationFrame(animate);
    },
    createPointStyle(angle) {
      // 根據(jù)朝向創(chuàng)建點的樣式
      return new Style({
        image: new Icon({
          src: require('@/assets/board.png'),
          scale: 0.1,
          rotation: -angle + (180 * Math.PI / 180), // 設(shè)置點的朝向
          anchor: [0.5, 0.7], // 設(shè)置錨點位置
        }),
      });
    }
  },
};
</script>
<style scoped>
.map {
  width: 100%;
  height: 800px;
}
</style>

服務(wù)器代碼如下:

 1、數(shù)據(jù)庫相關(guān):

// database.js
const { Client } = require('pg');
const axios = require('axios');
const fs = require('fs').promises;
const moment = require('moment-timezone');
// 配置數(shù)據(jù)庫連接
const client = new Client({
    user: 'postgres',
    host: 'loaclhost',
    database: 'postgres',
    password: 'root',
    port: 4321, // 默認(rèn)PostgreSQL端口
});
async function createTable() {
    const createTableQuery = `
        CREATE TABLE IF NOT EXISTS track_board_test (
            fid BIGINT PRIMARY KEY,
            id VARCHAR(255),
            name VARCHAR(255),
            mmsi VARCHAR(255),
            geom GEOMETRY(MultiPointM)
        );
        CREATE INDEX IF NOT EXISTS geom_index ON track_board_test USING GIST (geom);
    `;
    try {
        await client.query(createTableQuery);
        console.log('Table created successfully');
    } catch (err) {
        console.error('Error creating table:', err.stack);
    }
}
async function insertDataFromFile(filePath, isHttp) {
    try {
        let data;
        if (isHttp) {
            const response = await axios.get(filePath);
            data = response.data;
        } else {
            const rawData = await fs.readFile(filePath);
            data = JSON.parse(rawData);
        }
        for (const item of data.data) {
            const { id, mmsi, name, hisRecord } = item;
            let fid;
            if (id.startsWith("radar")) {
                fid = parseInt(id.substring("radar".length));
            } else {
                fid = parseInt(id);
            }
            const points = hisRecord.map(record => {
                const utcTime = moment.tz(record.updateTime, "Asia/Shanghai").utc().format('YYYY-MM-DD HH:mm:ss');
                return `ST_SetSRID(ST_MakePointM(${record.longitude}, ${record.latitude}, EXTRACT(EPOCH FROM TIMESTAMP '${utcTime}')), 4326)`;
            }).join(', ');
            const geom = `ST_Collect(ARRAY[${points}])`;
            const query = `
                INSERT INTO track_board_test (id, name, mmsi, geom, fid)
                VALUES ($1, $2, $3, ${geom}, $4)
                ON CONFLICT (fid) DO UPDATE
                SET id = EXCLUDED.id, name = EXCLUDED.name, mmsi = EXCLUDED.mmsi, geom = EXCLUDED.geom, fid = EXCLUDED.fid;
            `;
            await client.query(query, [id, name, mmsi, fid]);
        }
        console.log('數(shù)據(jù)插入成功');
    } catch (err) {
        console.error('插入數(shù)據(jù)時發(fā)生錯誤:', err);
    }
}
async function insertRandomData() {
    const insertRandomDataQuery = `
    DO $$
    DECLARE
        i INT;
    BEGIN
        FOR i IN 10010000..10015000 LOOP
            EXECUTE format(
                'INSERT INTO track_board_test (id, geom, fid) 
                VALUES (%L, 
                    (SELECT ST_Collect(
                        ARRAY(
                            WITH RECURSIVE points AS (
                                SELECT
                                    random() * 360 - 180 AS lon,
                                    random() * 180 - 90 AS lat,
                                    CAST(1716186468 + random() * 1000 AS INT) AS m,
                                    1 AS iteration,
                                    CEIL(random() * 99 + 1) AS max_iterations -- 隨機(jī)生成1到100之間的點數(shù)
                                UNION ALL
                                SELECT
                                    lon + (0.01 + random() * 0.09) * (CASE WHEN random() < 0.5 THEN 1 ELSE -1 END) AS lon,
                                    lat + (0.01 + random() * 0.09) * (CASE WHEN random() < 0.5 THEN 1 ELSE -1 END) AS lat,
                                    CAST(m + random() * 400 AS INT) AS m,
                                    iteration + 1,
                                    max_iterations
                                FROM points
                                WHERE iteration < max_iterations
                            )
                            SELECT ST_SetSRID(ST_MakePointM(lon, lat, m), 4326)
                            FROM points
                        )
                    )),
                    %L
                ) 
                ON CONFLICT (fid) DO NOTHING',
                'radar_' || i,
                i
            );
        END LOOP;
    END $$;    
    `;
    try {
        await client.query(insertRandomDataQuery);
        console.log('Random data insert successfully');
    } catch (err) {
        console.error('Error inserting random data:', err.stack);
    }
}
async function getAllData() {
    try {
        const query = `
            SELECT fid, id, name, mmsi, ST_X(dp.geom) AS Lng, ST_Y(dp.geom) AS Lat, ST_M(dp.geom) AS time
            FROM track_board_test,
            LATERAL ST_DumpPoints(geom) AS dp;
        `;
        const result = await client.query(query);
        return result.rows;
    } catch (err) {
        console.error('Error fetching data:', err.stack);
        return [];
    }
}
async function getTimeRange() {
    try {
        const query = `
            SELECT 
            MAX(max_time) AS max_time, 
            MIN(min_time) AS min_time
        FROM (
            SELECT 
                (SELECT MAX(ST_M(dp.geom)) FROM LATERAL ST_DumpPoints(track_board_test.geom) AS dp) AS max_time,
                (SELECT MIN(ST_M(dp.geom)) FROM LATERAL ST_DumpPoints(track_board_test.geom) AS dp) AS min_time
            FROM 
                track_board_test
        ) AS subquery;    
        `;
        const result = await client.query(query);
        const { max_time, min_time } = result.rows[0];
        return { minTime: min_time, maxTime: max_time };
    } catch (err) {
        console.error('Error executing query', err.stack);
        throw err;
    }
}
async function getPointsByTimestamp(timestamp, bbox) {
    try {
        const query = `
        WITH extracted_points AS (
            SELECT 
                tbt.fid, 
                (dp).geom AS point,
                ST_M((dp).geom) AS m_value
            FROM 
                track_board_test tbt
                CROSS JOIN LATERAL ST_DumpPoints(tbt.geom) AS dp
            WHERE
                ST_Intersects(tbt.geom, ST_MakeEnvelope($1, $2, $3, $4, 4326)) -- Add bbox filter
            ORDER BY fid
        ),
        min_max_times AS (
            SELECT 
                fid,
                MAX(CASE WHEN m_value <= $5 THEN m_value END) AS min_time,
                MIN(CASE WHEN m_value > $5 THEN m_value END) AS max_time
            FROM 
                extracted_points
            GROUP BY 
                fid
        ),
        min_points AS (
            SELECT 
                ep.fid,
                ep.m_value AS min_time,
                ep.point AS min_point
            FROM 
                extracted_points ep
            JOIN min_max_times mmt ON ep.fid = mmt.fid AND ep.m_value = mmt.min_time
        ),
        max_points AS (
            SELECT 
                ep.fid,
                ep.m_value AS max_time,
                ep.point AS max_point
            FROM 
                extracted_points ep
            JOIN min_max_times mmt ON ep.fid = mmt.fid AND ep.m_value = mmt.max_time
        )
        SELECT 
            mmt.fid,
            ST_X(ST_LineInterpolatePoint(ST_MakeLine(mp.min_point, mx.max_point), ($5 - mmt.min_time) / (mmt.max_time - mmt.min_time))) AS interpolated_longitude,
            ST_Y(ST_LineInterpolatePoint(ST_MakeLine(mp.min_point, mx.max_point), ($5 - mmt.min_time) / (mmt.max_time - mmt.min_time))) AS interpolated_latitude
        FROM 
            min_max_times mmt
            JOIN min_points mp ON mmt.fid = mp.fid
            JOIN max_points mx ON mmt.fid = mx.fid;
        `;
        const result = await client.query(query, [...bbox, timestamp]);
        return result.rows;
    } catch (err) {
        console.error('Error fetching interpolated points:', err.stack);
        return [];
    }
}
async function getLineGeometries(timestamp, bbox) {
    const query = `
        WITH extracted_points AS (
            SELECT
                fid,
                (ST_DumpPoints(geom)).geom AS point
            FROM track_board_test
            WHERE
                ST_Intersects(geom, ST_MakeEnvelope($1, $2, $3, $4, 4326)) -- Add bbox filter
        ),
        filtered_points AS (
            SELECT
                fid,
                point,
                ST_M(point) AS m_value
            FROM extracted_points
            WHERE ST_M(point) <= $5
        ),
        sorted_points AS (
            SELECT
                fid,
                point
            FROM filtered_points
            ORDER BY fid, m_value
        )
        SELECT
            fid,
            ST_MakeLine(point) AS line_geom
        FROM sorted_points
        GROUP BY fid;
    `;
    const result = await client.query(query, [...bbox, timestamp]);
    return result.rows;
}
module.exports = {
    client,
    createTable,
    insertDataFromFile,
    insertRandomData,
    getAllData,
    getTimeRange,
    getPointsByTimestamp,
    getLineGeometries
};

http接口相關(guān):

const express = require('express');
const cors = require('cors');
const {
    client,
    createTable,
    insertDataFromFile,
    insertRandomData,
    getAllData,
    getTimeRange,
    getPointsByTimestamp,
    getLineGeometries } = require('./database');
const app = express();
app.use(cors());
const port = 4325;
client.connect()
    .then(() => console.log('Connected to the database'))
    .catch(err => console.error('Connection error', err.stack));
createTable();
const filePath = './test.json'; // 替換為你的文件路徑
insertDataFromFile(filePath, false);
insertRandomData();
app.get('/all-data', async (req, res) => {
    try {
        const data = await getAllData();
        res.json(data);
    } catch (err) {
        res.status(500).json({ error: 'Internal Server Error' });
    }
});
// 創(chuàng)建一個API端點
app.get('/time-range', async (req, res) => {
    try {
        const { minTime, maxTime } = await getTimeRange();
        res.json({ minTime, maxTime });
    } catch (err) {
        console.error('Error fetching time range:', err.stack);
        res.status(500).json({ error: 'Internal Server Error' });
    }
});
app.get('/points', async (req, res) => {
    const timestamp = req.query.timestamp;
    const bbox = req.query.bbox.split(',').map(parseFloat); // 解析 bbox 參數(shù)為數(shù)組
    if (!timestamp) {
      return res.status(400).json({ error: 'Timestamp is required' });
    }
    try {
        const points = await getPointsByTimestamp(timestamp, bbox); // 將 bbox 參數(shù)傳遞給函數(shù)
        res.json(points);
    } catch (err) {
        res.status(500).json({ error: 'Internal Server Error' });
    }
});
app.get('/line-geometries', async (req, res) => {
    const timestamp = req.query.timestamp;
    const bbox = req.query.bbox.split(',').map(parseFloat); // 解析 bbox 參數(shù)為數(shù)組
    if (!timestamp) {
        return res.status(400).json({ error: 'Timestamp is required' });
    }
    try {
        const lineGeometries = await getLineGeometries(timestamp, bbox); // 將 bbox 參數(shù)傳遞給函數(shù)
        res.json(lineGeometries);
    } catch (err) {
        console.error('Error fetching line geometries:', err.stack);
        res.status(500).json({ error: 'Internal Server Error' });
    }
});
// 啟動服務(wù)器
app.listen(port, () => {
    console.log(`Server is running on http://localhost:${port}`);
});

小結(jié)

當(dāng)顯示全球范圍性能會有明顯卡頓,可能需要改進(jìn)算法。

到此這篇關(guān)于vue+openlayers+nodejs+postgis實現(xiàn)軌跡運動的文章就介紹到這了,更多相關(guān)vue軌跡運動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue中父組件向子組件通信的方法

    Vue中父組件向子組件通信的方法

    可以使用props將父組件的數(shù)據(jù)傳給子組件。子組件在接受數(shù)據(jù)時要顯示聲明props。下面通過一個例子給大家介紹Vue中父組件向子組件通信的方法,需要的朋友參考下吧
    2017-07-07
  • 在vue中動態(tài)修改css其中一個屬性值操作

    在vue中動態(tài)修改css其中一個屬性值操作

    這篇文章主要介紹了在vue中動態(tài)修改css其中一個屬性值操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • vue3響應(yīng)式Proxy與Reflect的理解及基本使用實例詳解

    vue3響應(yīng)式Proxy與Reflect的理解及基本使用實例詳解

    這篇文章主要為大家介紹了vue3響應(yīng)式Proxy與Reflect的理解及基本使用實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 詳解如何在vue中封裝axios請求并集中管理

    詳解如何在vue中封裝axios請求并集中管理

    這篇文章主要為大家詳細(xì)介紹了如何在vue中封裝axios請求并集中管理,w文中的示例代碼講解詳細(xì),具有一定的參考價值,有需要的小伙伴可以了解下
    2023-10-10
  • vue element-ui實現(xiàn)input輸入框金額數(shù)字添加千分位

    vue element-ui實現(xiàn)input輸入框金額數(shù)字添加千分位

    這篇文章主要介紹了vue element-ui實現(xiàn)input輸入框金額數(shù)字添加千分位,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • Django與Vue語法的沖突問題完美解決方法

    Django與Vue語法的沖突問題完美解決方法

    這篇文章主要介紹了Django與Vue語法的沖突問題完美解決方法,本文給大家分享了兩種解決方法,需要的朋友參考下吧
    2017-12-12
  • el-table實現(xiàn)嵌套表格的展示功能(完整代碼)

    el-table實現(xiàn)嵌套表格的展示功能(完整代碼)

    el-table中在嵌套一個el-table,這樣數(shù)據(jù)格式就沒問題了,主要就是樣式,將共同的列放到一列中,通過渲染自定義表頭render-header,將表頭按照合適的寬度渲染出來,本文給大家分享el-table實現(xiàn)嵌套表格的展示功能,感興趣的朋友一起看看吧
    2024-02-02
  • element ui里dialog關(guān)閉后清除驗證條件方法

    element ui里dialog關(guān)閉后清除驗證條件方法

    下面小編就為大家分享一篇element ui里dialog關(guān)閉后清除驗證條件方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • 在Vue中是如何封裝axios

    在Vue中是如何封裝axios

    這篇文章主要介紹在Vue中是如何封裝axios的相關(guān)資料,axios的封裝主要是幫助我們簡化代碼和利于后期的更新維護(hù),感興趣的小伙伴可以和小編一起來閱讀下面文章的具體內(nèi)容
    2021-10-10
  • Vuejs中使用markdown服務(wù)器端渲染的示例

    Vuejs中使用markdown服務(wù)器端渲染的示例

    這篇文章主要介紹了Vuejs 中使用 markdown的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11

最新評論