最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3使用threejs實(shí)現(xiàn)3D卡片水平旋轉(zhuǎn)效果的示例代碼

 更新時(shí)間:2024年04月29日 10:16:34   作者:vue_郵遞員  
這篇文章主要介紹了在vue3中使用threejs實(shí)現(xiàn)3D卡片水平旋轉(zhuǎn)效果,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

這個(gè)是根據(jù)three現(xiàn)有案例來(lái)模仿實(shí)現(xiàn),[原網(wǎng)址](three.js css3d - periodic table (threejs.org)

效果圖:

template部分

  <div class="content1" ref="containerRef">
    <div id="container" style="background-color: transparent"></div>
  </div>

script部分

import { onMounted,onUnmounted } from 'vue';
  import { useRouter } from 'vue-router';
  import * as THREE from 'three';
  import TWEEN from 'three/addons/libs/tween.module.js';
  import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
  import { CSS3DRenderer, CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
  import { getSiteList } from '@/api/periodictable';
  import { detailsInfo } from '@/views/mapDetail/data';
  const props = defineProps({
    id: {
      type: Number,
      defaults: '',
    },
  });
  const autoRotate = ref(true);
  const router = useRouter();
  const containerRef = ref();
  let camera, scene, renderer;
  let controls;

  let objects = [];
  const targets = { table: [], sphere: [], helix: [], grid: [], tablelist: [] };

  // 圖形初始化
  function init() {
    console.log('containerRef', containerRef.value.clientWidth, containerRef.value.clientHeight);
    camera = new THREE.PerspectiveCamera(40, containerRef.value.clientWidth / containerRef.value.clientHeight, 1, 10000);
    camera.position.z = 3000;

    scene = new THREE.Scene();

    renderer = new CSS3DRenderer({ alpha: true });
    renderer.setSize(containerRef.value.clientWidth, containerRef.value.clientHeight);
    document.getElementById('container').style.background = 'transparent';
    document.getElementById('container').appendChild(renderer.domElement);

    controls = new TrackballControls(camera, renderer.domElement);
    controls.minDistance = 500;
    controls.maxDistance = 6000;
    controls.addEventListener('change', render);
    controls.noPan = true
    controls.mouseButtons = {
      LEFT: THREE.MOUSE.RIGHT,
      RIGHT: THREE.MOUSE.LEFT,
    };
    getList({ type: 4, siteId: props.id });

    window.addEventListener('resize', onWindowResize);

    animate();
  }
  // 變換
  function transform(targets, duration) {
    TWEEN.removeAll();
    for (let i = 0; i < objects.length; i++) {
      const object = objects[i];
      const target = targets[i];

      new TWEEN.Tween(object.position)
        .to({ x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration)
        .easing(TWEEN.Easing.Exponential.InOut)
        .start();

      new TWEEN.Tween(object.rotation)
        .to({ x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration)
        .easing(TWEEN.Easing.Exponential.InOut)
        .start();
    }
    new TWEEN.Tween(this)
      .to({}, duration * 2)
      .onUpdate(render)
      .start();

    controls.reset();
    controls.noRotate = false;
  }

  //窗口監(jiān)聽(tīng)
  function onWindowResize() {
    console.log('2222');
    camera.aspect = containerRef.value.clientWidth / containerRef.value.clientHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(containerRef.value.clientWidth, containerRef.value.clientHeight);
    render();
  }

  // 圖形刷新
  function animate() {
    requestAnimationFrame(animate);
    if (autoRotate.value) {
      scene.rotation.y += 0.001; // 旋轉(zhuǎn)速度
    }
    objects.forEach((object) => {
      object.lookAt(camera.position); //卡片取消翻轉(zhuǎn)
    });
    TWEEN.update();
    controls.update();
    render();
  }

  // 圖形渲染
  function render() {
    renderer.render(scene, camera);
  }

  // 查找數(shù)據(jù)
  async function getList(query) {
    const { site } = await getSiteList(query);
    console.log('site', site);
    helixRender(site);
  }
  // 圓圈形狀
  function helixRender(data) {
    scene.clear();
    objects = [];
    targets.helix = [];
    targets.circle = [];
    Object.keys(detailsInfo).forEach((key, index) => {
      // 構(gòu)建元素
      const element = document.createElement('div');
      element.className = 'element1';
      element.style.backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')';
      element.onmousedown = function (e) {
        e.ctrlKey && getList({ type: 1, yearName: key });
      };

      // const number = document.createElement('div');
      // number.className = 'number';
      // number.textContent = index + 1;
      // element.appendChild(number);

      const symbol = document.createElement('div');
      symbol.className = 'symbol1';
      symbol.textContent = data[key] ;
      element.appendChild(symbol);

      const details = document.createElement('div');
      details.className = 'details';
      details.innerHTML = detailsInfo[key].name;
      element.appendChild(details);
      const objectCSS = new CSS3DObject(element);
      objectCSS.position.x = Math.random() * 4000 - 2000;
      objectCSS.position.y = Math.random() * 4000 - 2000;
      objectCSS.position.z = Math.random() * 4000 - 2000;

      scene.add(objectCSS);
      objects.push(objectCSS);
    });
    const radius = 400; // 設(shè)置圓形布局的半徑
    const vector = new THREE.Vector3(20, 20, 20);
    for (let i = 0, l = objects.length; i < l; i++) {
      const phi = (i / l) * 2 * Math.PI; // 分配每個(gè)對(duì)象在圓上的角度

      const object = new THREE.Object3D();
      object.position.x = radius * Math.cos(phi);
      object.position.y = 0;
      object.position.z = radius * Math.sin(phi);

      // 設(shè)置對(duì)象朝向圓心
      vector.x = object.position.x;
      vector.y = object.position.y;
      vector.z = object.position.z;
      object.lookAt(vector);

      targets.circle.push(object);
    }
    transform(targets.circle, 0);
    camera.position.z = 1100;
  }

  const setControls = (bool) => {
    controls.noZoom = bool; // 啟用縮放功能
    controls.noRotate = bool;
  };
  onMounted(() => {
    setTimeout(() => {
      init();
      animate();
    },200);
  });
  onUnmounted(()=>{
    window.removeEventListener('resize', onWindowResize);
  })
  defineExpose({
    setControls,
  });

style

<style lang="less" scoped>
  .content1 {
    height: 600px;
    width: 1000px;
    background-color: transparent !important;
    position: absolute;
    top: -290px;
    left: -122px;
  }
</style>
<style lang="less" >
  a {
    color: #8ff;
  }

  #menu {
    position: absolute;
    bottom: 20px;
    width: 100%;
    text-align: center;
  }

  .element1 {
    width: 120px;
    height: 130px;
    box-shadow: 0 0 12px rgb(0 255 255 / 50%);
    border: 1px solid rgb(127 255 255 / 25%);
    font-family: Helvetica, sans-serif;
    text-align: center;
    line-height: normal;
    cursor: default;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .element1:hover {
    box-shadow: 0 0 12px rgb(0 255 255 / 75%);
    border: 1px solid rgb(127 255 255 / 75%);
  }

  .element1 .number {
    position: absolute;
    top: 20px;
    right: 20px;
    font-size: 12px;
    color: rgb(127 255 255 / 75%);
  }

  .element1 .symbol1 {
    // position: absolute;
    // top: 15px;
    // left: 0;
    // right: 0;
    font-size: 16px;
    padding: 0 10px;
    margin-bottom: 20px;
    // height: 70px;
    // border:1px solid red;
    font-weight: bold;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
    white-space: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box; //將對(duì)象作為彈性伸縮盒子模型顯示。
    -webkit-box-orient: vertical; // 從上到下垂直排列子元素
    -webkit-line-clamp: 3; //顯示的行數(shù)
  }

  .element1.grid {
    width: 160px;
    height: 180px;
  }

  .element1 .grid-symbol {
    position: absolute;
    top: 35px;
    padding: 0 2px;
    left: 0;
    right: 0;
    font-size: 30px;
    font-weight: bold;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
    display: -webkit-box;
    -webkit-box-orient: vertical; /* 垂直排列子元素 */ /* 限制在兩行 */
    -webkit-line-clamp: 2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
  }

  .element1 .table-symbol {
    position: absolute;
    top: 35px;
    padding: 0 2px;
    left: 0;
    right: 0;
    font-size: 20px;
    font-weight: bold;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
    display: -webkit-box;
    -webkit-box-orient: vertical; /* 垂直排列子元素 */ /* 限制在兩行 */
    -webkit-line-clamp: 2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
  }

  .element1.publishname {
    width: 400px;
  }

  .element1.imageUrl {
    width: 400px;
    height: 340px;
  }

  .publishname .table-symbol {
    font-size: 36px;
  }

  .imageUrl .table-symbol {
    top: 3px;
    bottom: 3px;
  }

  .table-symbol .table-img {
    height: 100%;
    width: 100%;
  }

  .element1 .years {
    position: absolute;
    left: 6px;
    top: 6px;
    font-size: 14px;
    color: rgb(127 255 255 / 75%);
  }

  .element1 .subsymbol {
    position: absolute;
    top: 96px;
    left: 0;
    right: 0;
    font-size: 10px;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
  }

  .element1 .details {
    position: absolute;
    bottom: 15px;
    left: 0;
    right: 0;
    font-size: 14px;
    color: rgb(127 255 255 / 75%);
  }

  .element1 .table-details {
    position: absolute;
    bottom: 16px;
    left: 0;
    right: 0;
    font-size: 16px;
    color: rgb(127 255 255 / 75%);
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .grid-name {
    font-size: 40px;
    font-weight: bold;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
    background-color: rgb(0 127 127 / 59%);
    padding: 20px 30px;
    border-radius: 6px;
    position: relative;
  }

  .grid-name .level-num {
    position: absolute;
    border: 1px solid rgb(127 255 255 / 75%);
    background-color: rgb(0 127 127 / 59%);
    display: inline-block;
    font-size: 12px;
    padding: 2px 4px;
    border-radius: 4px;
    right: 1px;
    top: 1px;
  }

  .show-more {
    font-size: 22px;
    // font-weight: bold;
    color: rgb(255 255 255 / 75%);
    text-shadow: 0 0 10px rgb(0 255 255 / 95%);
    background-color: rgb(0 127 127 / 59%);
    padding: 10px 30px;
    border-radius: 6px;
  }
</style>
<style lang="less" scoped>
  .type-picker {
    position: absolute;
    bottom: 20px;
    left: 50%;
    margin-left: -52px;
    z-index: 99;

    :deep(.el-radio-button.is-active) {
      .el-radio-button__inner {
        background-color: rgb(88 88 88 / 80%);
      }
    }

    :deep(.el-radio-button__inner) {
      background-color: rgb(36 36 36 / 50%);
      border: none !important;
      color: rgb(255 255 255 / 90%);
      padding: 10px 14px;
      box-shadow: none;
    }

    :deep(.el-radio-button:first-child .el-radio-button__inner) {
      border-radius: 45px 0 0 45px;
    }

    :deep(.el-radio-button:last-child .el-radio-button__inner) {
      border-radius: 0 45px 45px 0;
    }
  }
</style>

以上就是vue3使用threejs實(shí)現(xiàn)3D卡片水平旋轉(zhuǎn)效果的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于vue3 threejs3D卡片水平旋轉(zhuǎn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue不能檢測(cè)到Object/Array更新的情況的解決

    Vue不能檢測(cè)到Object/Array更新的情況的解決

    本篇文章主要介紹了Vue不能檢測(cè)到Object/Array更新的情況的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Jenkins?Sidebar?Link插件實(shí)現(xiàn)添加側(cè)邊欄功能詳解

    Jenkins?Sidebar?Link插件實(shí)現(xiàn)添加側(cè)邊欄功能詳解

    這篇文章主要介紹了vue框架實(shí)現(xiàn)添加側(cè)邊欄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 基于Vue3實(shí)現(xiàn)SSR(服務(wù)端渲染)功能

    基于Vue3實(shí)現(xiàn)SSR(服務(wù)端渲染)功能

    在現(xiàn)代網(wǎng)頁(yè)開(kāi)發(fā)中,用戶體驗(yàn)日益成為網(wǎng)站成功的重要因素,從加載時(shí)間到SEO優(yōu)化,越來(lái)越多的開(kāi)發(fā)者開(kāi)始關(guān)注使用服務(wù)端渲染(SSR)來(lái)提升應(yīng)用的表現(xiàn),本文將深入探討 Vue 3 的 SSR 特性,并以示例代碼展示如何實(shí)現(xiàn)這一功能,需要的朋友可以參考下
    2024-11-11
  • vue3+element-plus實(shí)現(xiàn)兩個(gè)表格同步滾動(dòng)功能

    vue3+element-plus實(shí)現(xiàn)兩個(gè)表格同步滾動(dòng)功能

    現(xiàn)在需要兩個(gè)表格,為了方便對(duì)比左右的數(shù)據(jù),需要其中一邊的表格滾動(dòng)時(shí),另一邊的表格也跟著一起滾動(dòng),并且保持滾動(dòng)位置的一致性,本文給大家介紹vue3+element-plus實(shí)現(xiàn)兩個(gè)表格同步滾動(dòng)功能,感興趣的朋友一起看看吧
    2025-06-06
  • 在小程序/mpvue中使用flyio發(fā)起網(wǎng)絡(luò)請(qǐng)求的方法

    在小程序/mpvue中使用flyio發(fā)起網(wǎng)絡(luò)請(qǐng)求的方法

    這篇文章主要介紹了在小程序/mpvue中使用flyio發(fā)起網(wǎng)絡(luò)請(qǐng)求的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Vue實(shí)現(xiàn)動(dòng)態(tài)路由導(dǎo)航的示例

    Vue實(shí)現(xiàn)動(dòng)態(tài)路由導(dǎo)航的示例

    本文主要介紹了Vue實(shí)現(xiàn)動(dòng)態(tài)路由導(dǎo)航的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • vue yaml代碼編輯器組件問(wèn)題

    vue yaml代碼編輯器組件問(wèn)題

    這篇文章主要介紹了vue yaml代碼編輯器組件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Vue3父子組件間傳參通信的四種方式

    Vue3父子組件間傳參通信的四種方式

    近期學(xué)習(xí)vue3的父子組件之間的傳值,發(fā)現(xiàn)跟vue2的并沒(méi)有太大的區(qū)別,下面這篇文章主要給大家介紹了關(guān)于Vue3父子組件間傳參通信的四種方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • vue項(xiàng)目使用$router.go(-1)返回時(shí)刷新原來(lái)的界面操作

    vue項(xiàng)目使用$router.go(-1)返回時(shí)刷新原來(lái)的界面操作

    這篇文章主要介紹了vue項(xiàng)目使用$router.go(-1)返回時(shí)刷新原來(lái)的界面操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • 基于Element的組件改造的樹(shù)形選擇器(樹(shù)形下拉框)

    基于Element的組件改造的樹(shù)形選擇器(樹(shù)形下拉框)

    這篇文章主要介紹了基于Element的組件改造的樹(shù)形選擇器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02

最新評(píng)論

苏尼特左旗| 柳林县| 汉寿县| 林芝县| 区。| 自治县| 调兵山市| 调兵山市| 连云港市| 凌源市| 石家庄市| 鹤庆县| 剑阁县| 祁门县| 鹤峰县| 东山县| 信宜市| 榕江县| 宁强县| 佛教| 隆安县| 芜湖市| 象州县| 余干县| 临沂市| 大姚县| 汽车| 北海市| 栖霞市| 阳城县| 务川| 宁远县| 兰西县| 青龙| 罗山县| 上虞市| 曲松县| 龙海市| 明水县| 灵寿县| 安泽县|