vue3版本网页小游戏

news2024/11/18 11:32:55

目录

1.前言

2.实现过程

2.1目录

2.2文件介绍

3.核心逻辑分步骤详解

4.总结


1.前言

最近火爆全网的羊了个羊小程序,背景是根据官方介绍,“羊了个羊”是一款闯关消除小游戏,通关率不到0.1%。主要玩法为重叠的各类方块,需要在下方7个栏内完成消除(3个同类消除),其特点就是“极难”,也因此成为热门挑战。我也颇感兴趣,去玩了2把,的确很有乐趣,整理了一下思路,决定搞个vue3版本的网页版本,我看网上有react版本的了,vue3版本还没有,下面分别给出设计思路,实现方式,和玩法

设计思路:

1,先来一张背景图,网上搜一张草地图片

2,最底部设置七个槽位,有三个连续相同的就消除,槽位满了的话,挑战失败

3,中间的图层区域使用重叠的方式,可能是半重叠,可能是全重叠,只有第一层可以移入槽位,全部消除时,表示挑战成功!后续挑战是变化关卡的布局方式(多种排列方式)

4,点击事件的思路(内层不能点击,前置点击如果槽位满了还没有消除完,关卡的消除,消除动作 和 添加爆炸效果,进入下一关,挑战失败)

5,辅助类函数:判断是否过关,消除函数,实现爆炸💥效果,控制关卡

实现方式:

vue3配合pinia实现数据驱动页面

玩法:

使用关卡模式,从第1关简单到2困难,3关复杂,这里的关卡只是数据的多少变化而已,可以设计出无数关卡,这里前端模拟json数据,使用对象json

效果演示:

在线体验 :

KinHKinhttps://rondsjinhuajin.github.io/DemoVue/#/

源码地址:

在github欢迎follow和star,感谢可爱的各位看官大佬~❤️

2.实现过程

2.1目录

2.2文件介绍

 入口文件index.vue,设计背景色

<script setup lang='ts'>
import Header from "./components/Header.vue";
import Main from "./components/Main.vue";
</script>

<template>
  <div class="sheep-wrap">
    <div class="sheep">

      <div class="sheep-wrap">
        <div class="sheep">
          <Header />
          <Main />
        </div>
      </div>
    </div>
  </div>

</template>
<style scoped lang='less'>
.sheep-wrap {
  .sheep {
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    padding-bottom: 20px;
  }
  
  width: 100%;
  height: calc(100vh - 60px);
  background: url("../../assets/images/sheep.png") center no-repeat;
  background-size: cover;
}
</style>

Header.vue文件,文字动效,配合pinia显示第几关

<script lang='ts' setup>
import { useSheepStore } from "@/stores/sheep";
const store = useSheepStore();
</script>

<template>
  <div class="sheep-header">
    <div>第{{ store.step + 1 }}关</div>
    <div>
      <span class="l">羊了个羊🐑vue3版本</span
      ><span
        style="font-size: 14px;font-family: 'Times New Roman', Times, serif';"
        >(KinHKin)</span
      >
    </div>
  </div>
</template>
<style scoped lang="less">
.flex-center {
  display: flex;
  align-items: center;
}
.sheep-header {
  padding-top: 2rem;
  text-align: center;
  letter-spacing: 0.2rem;
  font-size: 1.5rem;
  color: #fff;
  border-bottom: 1px solid #1d9614;
  padding-bottom: 1rem;
  margin-bottom: 2rem;
  div .l {
    background-image: -webkit-linear-gradient(
      left,
      #1d9614,
      #fff 25%,
      #666 50%,
      #e6d205 75%,
      #fff
    );
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    -webkit-background-size: 200% 100%;
    -webkit-animation: maskedAnimation 4s infinite linear;
    padding-right: 8px;
  }
}
@keyframes maskedAnimation {
  0% {
    background-position: 0 0;
  }

  100% {
    background-position: -100% 0;
  }
}
</style>

Main.vue文件是核心文件,作用是引入颜色,控制关卡,设置关卡数据,如何消除,增加爆炸动效,控制交互逻辑等。

<script setup lang="ts">
import { ref, type Ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { useSheepStore } from "@/stores/sheep";
// 关卡数据
import data from "./data.json";
// 颜色
import constants from "./constants";
// pinia 控制关卡
const store = useSheepStore();
// 七个槽位
// const footerList = ref([0, 1, 2, 3, 4, 5, 6]);
const footerList: Ref<Array<any> | [any]> = ref([]);

const colors = ref(constants.colors);

// 关卡响应式
const totalList: Ref<Array<any> | [any]> = ref([]);
totalList.value = data["list1"]; // 默认第一关

// 控制动画效果结束才能点击
const isNotClick = ref(false);

// 点击控制事件
function handleClick(
  i: number,
  k: number,
  onei: { oneSub: string | Array<string> },
  onek: number,
  oneiSub: Array<number>,
  onekSub: number
) {
  console.log(i, k, onei, onek, oneiSub, onekSub, "测试");
  if (isNotClick.value) {
    return false;
  }
  // 内层不能点击
  if (onekSub !== onei.oneSub.length - 1) {
    return false;
  }

  // 前置点击如果槽位满了还没有消除完
  fullFun()

  // 关卡的消除
  let tempList = fixFun(k, onekSub, onek, oneiSub)

  // 消除动作 和 添加爆炸效果
  if (footerList.value.length > 2) {
    isNotClick.value = true
    const { list, flag } = eliminationFunction(footerList.value)
    footerList.value = list;
    if (flag) {
      footerList.value = addBoomFunction(footerList.value);
    }
    setTimeout(() => {
      const { list, flag } = eliminationFunction(footerList.value)
      footerList.value = list;
      isNotClick.value = false
    }, 1000);

    // 进入下一关
    nextFun(tempList)
  }
  // 挑战失败
  failFun(tempList)

  console.log(footerList, tempList, "tempList");
}
// full
function fullFun() {
  if (footerList.value.length === 7) {
    ElMessage.closeAll();

    ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
      confirmButtonText: "确定",
      type: "warning",
      showClose: false,
    }).then(() => {
      location.reload();
    });
    return false;
  }
}
// fix
function fixFun(k: number, onekSub: number, onek: number, oneiSub: Array<number>) {
  const { value } = totalList;

  let tempList = JSON.parse(JSON.stringify(value));

  for (let i = 0; i < tempList.length; i++) {
    const one = tempList[k].one;
    for (let j = 0; j < one.length; j++) {
      const oneSub = one[onek];
      for (let k = 0; k < oneSub.oneSub.length; k++) {
        if (onekSub === k) {
          const footItem = oneSub.oneSub.splice(onekSub);
          break;
        }
      }
    }
  }
  footerList.value.push(oneiSub);
  totalList.value = tempList;
  return tempList
}
//fail
function failFun(tempList: any[]) {
  setTimeout(() => {
    if (footerList.value.length > 0 && !jugeList(tempList)) {
      ElMessage.closeAll();

      ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
        confirmButtonText: "确定",
        type: "warning",
        showClose: false,
      }).then(() => {
        location.reload();
      });
      return false;
    }
  }, 1002)
}
// next
function nextFun(tempList: any[]) {
  setTimeout(() => {
    if (!footerList.value.length && !jugeList(tempList)) {
      // debugger
      ElMessage.closeAll();
      ElMessage.success("恭喜您,挑战成功!进入下一关");
      store.step++;
      const inStep: string = "list" + (store.step + 1);
      totalList.value = JSON.parse(JSON.stringify(data))[inStep];
      footerList.value = [];
    }
  }, 1001)
}
// 判断是否过关
function jugeList(list: any[]) {
  let temp: any = [];
  list?.forEach((oeni: { one: any }) => {
    oeni?.one?.forEach((sub: { oneSub: any }) => {
      temp = [...temp, ...sub.oneSub];
    });
  });
  return temp.length;
}

// 消除函数
function eliminationFunction(list: any[]) {
  let flag: boolean = false;
  for (let k = 0; k < list.length - 2; k++) {
    const temp = list;
    const arr = temp.slice(k, k + 3);
    console.log(k, arr);
    if (arr[0] === arr[1] && arr[1] === arr[2] && arr[0] === arr[2]) {
      list.splice(k + 2);
      list.splice(k + 1);
      list.splice(k, 1);
      flag = true
      break;
    }
  }

  return { list, flag };
}

// 实现爆炸💥效果
function addBoomFunction(list: any[]) {
  const temp = JSON.parse(JSON.stringify([...list, ...['boom', 'boom', 'boom']]))
  return temp;
}
</script>

<template>
  <div class="sheep-main">
    <div class="sheep-main-wrap">
      <template v-for="(i, k) in totalList" :key="'i' + k">
        <el-row v-if="i.one">
          <el-col :span="8" v-for="(onei, onek) in i.one" :key="'i' + onek">
            <div class="pic-list">
              <div class="pic-list-item" v-for="(oneiSub, onekSub) in onei.oneSub"
                :style="!onei.full ? `--i:${onekSub}` : `--i:0`"
                :class="onei.full && onei.oneSub.length > 1 ? 'true' : ''" :key="'i' + onekSub"
                @click="handleClick(i, k, onei, onek, oneiSub, onekSub)">
                <el-icon class="fz" v-if="oneiSub === 0">
                  <StarFilled :color="colors[0]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 1">
                  <Aim :color="colors[1]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 2">
                  <Grid :color="colors[2]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 3">
                  <HelpFilled :color="colors[3]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 4">
                  <Star :color="colors[4]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 5">
                  <Menu :color="colors[5]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 6">
                  <Camera :color="colors[6]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 7">
                  <Bicycle :color="colors[7]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 8">
                  <IceTea :color="colors[8]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 9">
                  <ColdDrink :color="colors[9]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 10">
                  <CoffeeCup :color="colors[10]" />
                </el-icon>
              </div>
            </div>
          </el-col>
        </el-row>
      </template>
    </div>

    <div class="sheep-footer flex-center">
      <div v-for="(ii, k) in footerList" :key="'ii' + k" class="sheep-footer-items">
        <el-icon class="fz" v-if="ii === 0">
          <StarFilled :color="colors[0]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 1">
          <Aim :color="colors[1]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 2">
          <Grid :color="colors[2]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 3">
          <HelpFilled :color="colors[3]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 4">
          <Star :color="colors[4]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 5">
          <Menu :color="colors[5]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 6">
          <Camera :color="colors[6]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 7">
          <Bicycle :color="colors[7]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 8">
          <IceTea :color="colors[8]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 9">
          <ColdDrink :color="colors[9]" />
        </el-icon>
        <el-icon class="fz" v-if="ii === 10">
          <CoffeeCup :color="colors[10]" />
        </el-icon>
        <div class="boom-class" v-if="ii === 'boom'">💥</div>
      </div>
    </div>
  </div>
</template>
<style scoped lang="less">
.flex-center {
  display: flex;
  align-items: center;
}

.el-row {
  // margin-top: 3rem;
  height: 28%;
}

.fz {
  font-size: 3rem;
  border: 1px solid #dfe5f9;
  // box-shadow: 2px 2px 10px #f3f6fe;

  background: #f3f6fe;
  border-radius: 5px;
}

.pic-list {
  position: relative;
  width: 100%;
  height: 100%;

  &-item {
    position: absolute;
    left: 10vw;
    cursor: pointer;
    transition: all 0.3s;

    &:nth-child(1n) {
      top: calc(var(--i) * 1.5rem);
    }

    &.true {
      box-shadow: 0 -55px 0 0 #dfe5f9 inset;
    }

    // &:nth-child(even) {
    //   top: 2rem;
    // }
  }
}

.sheep-main {
  flex: 1;

  &-wrap {
    height: calc(100% - 80px);
  }
}

.sheep-footer {
  height: 80px;
  width: 100%;
  // border: 2px solid #298df9;
  border: 2px solid #778899;
  background: #010206;

  .sheep-footer-items {
    height: 80px;
    width: calc(100% / 7);
    margin-left: 8px;
    display: flex;
    align-items: center;
    justify-content: center;

    .boom-class {
      font-size: 3rem;
      animation: myMove 3s ease-in-out infinite;
    }

    @keyframes myMove {
      0% {
        opacity: 1;
      }

      100% {
        opacity: 0;
      }
    }

    // border-right: 1px solid #dfe5f9;
  }
}
</style>

3.核心逻辑分步骤详解

import { ref, type Ref } from "vue";

import { ElMessage, ElMessageBox } from "element-plus";

import { useSheepStore } from "@/stores/sheep";

// 关卡数据

import data from "./data.json";

// 颜色

import constants from "./constants";

// pinia 控制关卡

const store = useSheepStore();

首先引入data.json数据是渲染中间的页面内容,即是:

中间的就叫卡片区域吧,卡片分为半个遮挡和整个遮挡,在data数据里面配置:

"full": true

 默认是半个遮挡,配置了"full": true就表示这块的卡片是全遮挡的效果:

:style="!onei.full ? `--i:${onekSub}` : `--i:0`"

:class="onei.full && onei.oneSub.length > 1 ? 'true' : ''" :key="'i' + onekSub"

css: 使用了var的变量形式,来控制是否需要top下移,&.true来控制是否有下一级的卡片的样式

&:nth-child(1n) {

top: calc(var(--i) * 1.5rem);

}

&.true {

        box-shadow: 0 -55px 0 0 #dfe5f9 inset;

}

data.json里面的数据oneSub的选值范围是:0-10

这和dom渲染层的息息相关:卡片使用的是简单的icon也可以是其他类型的元素,你觉得好看即可。

                <el-icon class="fz" v-if="oneiSub === 0">
                  <StarFilled :color="colors[0]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 1">
                  <Aim :color="colors[1]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 2">
                  <Grid :color="colors[2]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 3">
                  <HelpFilled :color="colors[3]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 4">
                  <Star :color="colors[4]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 5">
                  <Menu :color="colors[5]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 6">
                  <Camera :color="colors[6]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 7">
                  <Bicycle :color="colors[7]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 8">
                  <IceTea :color="colors[8]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 9">
                  <ColdDrink :color="colors[9]" />
                </el-icon>
                <el-icon class="fz" v-if="oneiSub === 10">
                  <CoffeeCup :color="colors[10]" />
                </el-icon>

这里只提供11中卡片的效果,可以扩展添加,需要修改代码。

接下来是:

// 七个槽位

// const footerList = ref([0, 1, 2, 3, 4, 5, 6]);

const footerList: Ref<Array<any> | [any]> = ref([]);

const colors = ref(constants.colors);

// 关卡响应式

const totalList: Ref<Array<any> | [any]> = ref([]);

totalList.value = data["list1"]; // 默认第一关

// 控制动画效果结束才能点击

const isNotClick = ref(false);

7个槽位在底部需要变化展示,做成响应式。totalList是动态变化的卡片数据集。totalList.value = data["list1"] ,默认第一关。爆炸💥的电话效果有延迟,需要控制在结束之后才能进行卡片的点击。

然后就是核心的卡片点击事件,需要做哪些逻辑控制呢?先看源代码,已经提前做了备注:

// 点击控制事件
function handleClick(
  i: number,
  k: number,
  onei: { oneSub: string | Array<string> },
  onek: number,
  oneiSub: Array<number>,
  onekSub: number
) {
  console.log(i, k, onei, onek, oneiSub, onekSub, "测试");
  if (isNotClick.value) {
    return false;
  }
  // 内层不能点击
  if (onekSub !== onei.oneSub.length - 1) {
    return false;
  }

  // 前置点击如果槽位满了还没有消除完
  fullFun()

  // 关卡的消除
  let tempList = fixFun(k, onekSub, onek, oneiSub)

  // 消除动作 和 添加爆炸效果
  if (footerList.value.length > 2) {
    isNotClick.value = true
    const { list, flag } = eliminationFunction(footerList.value)
    footerList.value = list;
    if (flag) {
      footerList.value = addBoomFunction(footerList.value);
    }
    setTimeout(() => {
      const { list, flag } = eliminationFunction(footerList.value)
      footerList.value = list;
      isNotClick.value = false
    }, 1000);

    // 进入下一关
    nextFun(tempList)
  }
  // 挑战失败
  failFun(tempList)

  console.log(footerList, tempList, "tempList");
}

首先是函数的签名,接受最上层级的i对象,k索引,然后是中层的onei对象,onek索引,最后是父级的oneiSub对象,onekSub索引。判断条件需要前置,判断能否点击isNotClick,内层不能点击

if (isNotClick.value) {

        return false;

}

// 前置点击如果槽位满了还没有消除完

fullFun()函数判断如果槽位满了还没有消除完,就是挑战失败

function fullFun() {
  if (footerList.value.length === 7) {
    ElMessage.closeAll();

    ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
      confirmButtonText: "确定",
      type: "warning",
      showClose: false,
    }).then(() => {
      location.reload();
    });
    return false;
  }
}

如何添加爆炸💥效果:

思路是在三个相同消除之后添加,添加在totalList数据之中 ,效果展示完成之后立即进行totalList数据重置操作。


  // 关卡的消除
  let tempList = fixFun(k, onekSub, onek, oneiSub)

  // 消除动作 和 添加爆炸效果
  if (footerList.value.length > 2) {
    isNotClick.value = true
    const { list, flag } = eliminationFunction(footerList.value)
    footerList.value = list;
    if (flag) {
      footerList.value = addBoomFunction(footerList.value);
    }
    setTimeout(() => {
      const { list, flag } = eliminationFunction(footerList.value)
      footerList.value = list;
      isNotClick.value = false
    }, 1000);

    // 进入下一关
    nextFun(tempList)
  }

css 添加的方法:

    .boom-class {
      font-size: 3rem;
      animation: myMove 3s ease-in-out infinite;
    }

    @keyframes myMove {
      0% {
        opacity: 1;
      }

      100% {
        opacity: 0;
      }
    }

消除函数eliminationFunction逻辑的控制,flag用来进行是否成功消除:


// 消除函数
function eliminationFunction(list: any[]) {
  let flag: boolean = false;
  for (let k = 0; k < list.length - 2; k++) {
    const temp = list;
    const arr = temp.slice(k, k + 3);
    console.log(k, arr);
    if (arr[0] === arr[1] && arr[1] === arr[2] && arr[0] === arr[2]) {
      list.splice(k + 2);
      list.splice(k + 1);
      list.splice(k, 1);
      flag = true
      break;
    }
  }

  return { list, flag };
}

添加addBoomFunction爆炸函数:

// 实现爆炸💥效果
function addBoomFunction(list: any[]) {
  const temp = JSON.parse(JSON.stringify([...list, ...['boom', 'boom', 'boom']]))
  return temp;
}

挑战失败如何判断呢?

//fail
function failFun(tempList: any[]) {
  setTimeout(() => {
    if (footerList.value.length > 0 && !jugeList(tempList)) {
      ElMessage.closeAll();

      ElMessageBox.alert("挑战失败,点击确定返回!", "Warning", {
        confirmButtonText: "确定",
        type: "warning",
        showClose: false,
      }).then(() => {
        location.reload();
      });
      return false;
    }
  }, 1002)
}

jugeList函数是对目前存在的卡片集合进行长度判断,如何卡片不存在,但是槽位的数据不为空的情况下,说明没有消除完,就判断要重新开始挑战: 

// 判断是否过关
function jugeList(list: any[]) {
  let temp: any = [];
  list?.forEach((oeni: { one: any }) => {
    oeni?.one?.forEach((sub: { oneSub: any }) => {
      temp = [...temp, ...sub.oneSub];
    });
  });
  return temp.length;
}

最后是挑战成功就可以进行下一关:

// next
function nextFun(tempList: any[]) {
  setTimeout(() => {
    if (!footerList.value.length && !jugeList(tempList)) {
      // debugger
      ElMessage.closeAll();
      ElMessage.success("恭喜您,挑战成功!进入下一关");
      store.step++;
      const inStep: string = "list" + (store.step + 1);
      totalList.value = JSON.parse(JSON.stringify(data))[inStep];
      footerList.value = [];
    }
  }, 1001)
}

如何卡片不存在,但是槽位的数据为空的情况下,说明消除完了,就可以进入下一关进行挑战,难度也将升级!

4.总结

最近是由于玩了羊了个羊的小程序,有所感悟,思考了这个游戏的整体的玩法,如何去操作,然后想到了可以实现一个前端网页版本的羊了个羊,这里面有一些自己的设计思考是很重要的,花了一个星期左右来实现,中间遇到了如何消除,如何控制挑战失败,成功的问题,并且一一解决了,可以想到如果前端来做这个游戏怎么在最优的方案上,书写可以扩展的dom,来适配很多不同的关卡的元素或者是我们需要什么样的数据结构,方便后续的关卡的升级。这里解决的方案是配合json,数据是数组嵌套类型,元素是需要循环来调用的,什么类型的卡片是需要提前有个范围的,这样是可扩展的。最后的操作,或者撤销,恢复等操作(这里没有实现)本质上也是对于数据的操作。终而言之:数据驱动页面,才是我们追求的。最后,各位同学一起多思考一下背后的实现,让我们用技术来创作更多有趣的事情吧~❤️
 

个人主页:KinHKin(五年前端)的博客_CSDN博客-vue,css,中秋活动领域博主

在线演示:KinHKin

fllow我的github:   rondsjinhuajin (承吾) · GitHub

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS选择器(nth-child)

:nth-child()这个选择符括号内可以写/- an b &#xff08;a&#xff0c;b均为整数&#xff09;或者关键字 因为工作中有遇到要隐藏列表第三个子元素之后的所有子元素&#xff0c;所以有用到这个选择器&#xff0c;记录一下 (1) nth-child(a) 当括号里只写一个数字&#xff…

元素垂直居中的五种方式

元素内容垂直居中 本文介绍&#xff1a; 元素标签内的内容垂直居中有两种思路&#xff0c; 第一种思路是将元素内容利用行高或者内边距padding属性设置 第二种思路是子盒子在父盒子中垂直居中&#xff0c;利用flex布局或者position定位方式 五种方式实现元素内容垂直居中第一种…

解决echarts报错Cannot read properties of null (reading ‘getAttribute‘)

前言 最近在写 echarts 的时候碰到了这么一个报错&#xff0c;如下图。造成报错的原因是因为 echarts 的图形容器还未生成就对其进行了初始化&#xff0c;下面几种方法是经本人自测最有效的解决方案。 报错截图 解决方案&#xff1a; 1. this.$nextTick 该方法思路是将回调延迟…

Vue|样式绑定

class 与 style 是 HTML 元素的属性&#xff0c;用于设置元素的样式&#xff0c;我们可以用 v-bind 来设置样式属性。Vue.js v-bind 在处理 class 和 style 时&#xff0c; 专门增强了它。表达式的结果类型除了字符串之外&#xff0c;还可以是对象或数组。 文末名片获取源码 精…

【vue 组件化开发 一 】组件基本使用、全局和局部组件、父组件和子组件的区别

目录 前言&#xff1a; 完整内容请关注&#xff1a; 一、组件的基本使用 二、全局组件和局部组件 全局注册&#xff0c;通过 Vue.component 局部注册&#xff0c;通过 components:{} 全局组件 局部组件 三、父组件和子组件的区别 前言&#xff1a; 完整内容请关注&am…

vue2中使用axios,以及axios拦截器的配置

目录 一、vue2项目中如何实现异步请求 1、axios&#xff1a;是一个基于Promise的网络请求库。既可以在node.js&#xff08;服务器端&#xff09;使用&#xff0c;也可以在浏览器端使用 2、vue中的使用方法 ​ &#xff08;2&#xff09;引用方法&#xff1a; ​ A、原生的…

HTML侧边导航栏

HTML侧边导航栏 简介&#xff1a;本文用最简洁的语言&#xff0c;来教会读者&#xff0c;如果用htmlcss来制作&#xff0c;侧边导航栏&#xff0c;本案例以手机商城中的部分为例子来制作。 第一步&#xff1a;构建框架 <body><!-- 首先确定导航栏中的内容 每个内容…

【vue 项目】el-upload 上传文件以及回显照片和下载文件

本次需求是上传多种固定格式的文件&#xff0c;且回显的时候&#xff0c;图片可以正常显示&#xff0c;文件可以进行下载 主要采用element的el-upload组件实现 1、文件上传 先看下&#xff0c;上传文件效果图 点击上传将文件放到网页&#xff0c;还有一个点击确定的按钮再上传…

猿创征文|【Typescript入门】常用数据类型(3)

&#x1f373;作者&#xff1a;贤蛋大眼萌&#xff0c;一名很普通但不想普通的程序媛\color{#FF0000}{贤蛋 大眼萌 &#xff0c;一名很普通但不想普通的程序媛}贤蛋大眼萌&#xff0c;一名很普通但不想普通的程序媛&#x1f933; &#x1f64a;语录&#xff1a;多一些不为什么的…

Vue项目中的接口调用

在企业开发过程中&#xff0c;往往有着明确的前后端的分工&#xff0c;前端负责接收、使用接口&#xff0c;后端负责编写、处理接口。 对于前端如何使用接口&#xff0c;今天在Vue中进行讲解。 一个项目往往由这几个部分组成。 其中在src文件夹中&#xff0c;&#xff0c;有这…

windows系统完全卸载并重装Node(亲测可用)

windows系统完全卸载并重装Node(亲测可用) 完成上述6步之后开始重新下载配置Node 根据自己的需要下载对应版本即可 安装完成查看 查看是否安装成功 A、node -v 查看 node 版本 B、npm -v 查看 npm 版本 2、安装完成后&#xff0c;文件目录如下图 如果 npx 为 5.2.0&#xf…

第十四届蓝桥杯Web应用开发—模拟赛3期--网页PPT--蓝桥校园一卡通--心愿便利贴

文章目录1&#xff1a;网页PPT (5分) ✔✔✔2&#xff1a;蓝桥校园一卡通 &#xff08;10分&#xff09;✔✔✔3&#xff1a;心愿便利贴 (15分) ✔✔✔1&#xff1a;网页PPT (5分) ✔✔✔ switchPage( ) switchPage( ){ if(activeIndex 0 ){$(".btn.left").addClas…

浅谈vue中的$含义及其用法($xxx引用的位置)

看了各个帖子的描述&#xff0c;还是未能参透$在vue中所想发挥的本意&#xff0c;将一些一知半解的理解摘抄下来&#xff0c;顺带附上自己常见的用法&#xff0c;以加深理解和记忆。 摘抄 这些只是Vue的命名规则&#xff0c;为了区分普通变量属性&#xff0c;避免我们自己声明…

前端开发一枚,入职前自学的感觉不难,为什么工作起来很吃力?

前言 我是软件工程专业&#xff0c;学前端之前&#xff0c;学过 C/C、Java、PHP、.net 成绩还不错基本都是90多分。感觉自己干后端也不吃力。实验室里面的项目都是前后都写。最爱 PHP&#xff0c;本以为以后就走上PHP后端工程师的道路了。 由于项目需要的原因&#xff0c;后来…

关于我的家乡html网页设计完整版,10个以家乡为主题的网页设计与实现

&#x1f4c2;文章目录​​二、&#x1f4da;网站介绍​​​​三、&#x1f517;网站效果​​​​▶️1.视频演示​​​​&#x1f9e9; 2.图片演示​​​​四、&#x1f492; 网站代码​​​​&#x1f9f1;HTML结构代码​​​​&#x1f3e0;CSS样式代码​​​​五、&#x1…

Vue中实现自定义excel下载

最近在工作中遇到一个需求&#xff0c;就是需要在前端实现一个错误模板Excel的下载功能。 实现下载有两种方式&#xff0c;一种是后端生成一个excel&#xff0c;放在服务器指定目录下&#xff0c;然后前端直接去后端拿。第二种是后端传给前端一个json的list&#xff0c;前端用…

vue 中使用自定义字体

1.先下载字体 2.在新建的font.css文件中加入下面代码引入字体 font-face { font-family: MSYH; src: url(阿里巴巴普惠体 L.ttf); font-weight: normal; font-style: normal; } font-face { font-family: HY; src: url(汉仪天宇风行体W.ttf); font-weight: normal; f…

React Hooks概述及常用的Hooks介绍

React Hooks概述及常用的Hooks介绍1 为什么会有Hooks2 Hooks的含义3 Hooks的用法3.1 useState()&#xff1a;状态钩子3.2 useEffect()&#xff1a;副作用钩子3.3 useCallback()&#xff1a;记忆函数3.4 useMemo()&#xff1a;记忆组件3.5 useRef()&#xff1a;保存引用值3.6 us…

【Fiddler Everywhere】史上最强抓包工具(安装 修改教程)

一、Fiddler简介 Fiddler Everywhere 是啥&#xff1f; 从名称上来看&#xff0c;就大概能猜出它的寓意&#xff0c;官方也通过一段话&#xff0c;解释了Fiddler Everywhere的作用: Fiddler Everywhere is a web debugging proxy for any browser, any application, any proc…

WEB核心【请求转发(阶段重点)】第六章

目录 1&#xff1a;请求转发【阶段重点】 1.1:语法格式及转发使用 1.2:request域对象 1.3:小结&#xff1a;请求转发间做数据传递 1.4:请求转发访问受保护目录 1&#xff1a;请求转发【阶段重点】 1.1:语法格式及转发使用 格式&#xff1a;forward:/要跳转的程序或者页面…