js和vue巩固指引

一、环境:

1、安装vscode

2、需要安装一个叫node的东西,如果安装了下图就可以执行。

Node.js 提供了一个 ++可以在非浏览器环境下 执行 JavaScript 代码的++ 环境

(还包含,npm工具,就可以装东西了,所以需要装好node.js)
可以用来验证有没有node.js

官网安装指导

配置npm

复制代码
# 查看
npm config get prefix   # 查看   全局安装目录   npm install xxx -g  时,会吧东西装进去
npm config get cache    # 查看   全局缓存目录

# 设置重新修改(C盘不好)---先新建文件(就建在安装的nodejs里面吧一般)
npm config set prefix "D:\soft\nodejs\node_global"
npm config set cache "D:\soft\nodejs\node_cache"

配置环境变量

在安装目录中,cmd 里, 可以 npm config list ,

其他地方如果不行,要配置环境变量, 安装时好像自动配上了,就是在系统变量path中加一个 安装目录路径就行、和上面安装指导有出入。

设置镜像源为淘宝源

复制代码
npm config set registry https://registry.npm.taobao.org      # 过期
npm config set registry https://registry.npmmirror.com    # 最新
npm config list # 查看验证

npm --version

npm安装

全局安装

尝试安装nprogress

其他局部不用安装直接使用?(gpt说不能用)

局部安装

直接如:npm install screenfull@5.2.0, 安装后有package.json文件,里面记录有哪些包, node_modules文件夹里放实际的包

生产依赖和开发依赖关系分享

局部安装分装到生产依赖,还是开发依赖
默认为生产依赖

加 参数 --save-dev 或 -d 就保存为开发依赖:

本地运行时,其实不管是哪种,但是上线后,通常选择 生产依赖,在开发过程中,就把一些辅助工具的依赖,装到开发依赖

总结: 初学时安装,就都不加 -d , 当你知道它是打包工具,测试工具,等辅助工具时,就最好加上-d。

二、快速使用vue包学习

本来需要使用npm xxx 创建的vue项目+ 初始化调试,我们先不管了,直接解压里面的压缩包来用

提取码:iqvy

解压后,目录中package.json 中,name 就是项目名,可以改成自己喜欢的,然后把外层的文件名换一样的, 这样 就和 npm安装 是一样的效果了。

然后终端执行:npm install (要把packagejson中需要的插件,源码给下载好,生成node_modules文件)

仍然需要做一些准备工作:

1. 装插件 vetur (.vue文件高亮, 以及保存时代码风格化代码)

右键插件的【扩展配置】, 点stting.json。进行配置

javascript 复制代码
{
    "vetur.completion.scaffoldSnippetSources": {
        
        "workspace": "💼",
        "user": "🗒️",
        "vetur": "✌"
    },
    "[vue]":{
        "editor.defaultFormatter": "octref.vetur",
        "editor.detectIndentation": false,//缩进
        "editor.tabSize": 4,//缩进大小
        "editor.formatOnSave": true //保存自动格式化

    },
    "[python]": {
        "editor.formatOnType": true
    },
    "python.autoComplete.extraPaths": [],
    "python.analysis.extraPaths": []
}

2. 其他插件-下面有代码补全的功效

vue 3 snippets

vue vscode snippets

其他(如果不懂的话可以装一下这些,具体啥用我也不知道)

eslint先别装,它好像是限制代码格式的,不装为好

ESLint 插件 的主要功能是帮助你实时检查代码中的错误和规范问题,它会根据配置的规则自动检测并标记出代码中的潜在问题。)

如果已经装了 eslint , 那么项目下的.eslintrc.js, 可以下面这样设置

javascript 复制代码
module.exports = {
  root: true,
  env: {
    node: true
  },
  extends: [
    'plugin:vue/vue3-essential',
    '@vue/standard'
  ],
  parserOptions: {
    parser: '@babel/eslint-parser',
    requireConfigFile: false
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'space-before-function-paren': 0, // 关闭在函数定义的左括号前强制使用一致的间距
    'eol-last': 0,                    // 关闭在文件末尾至少强制执行一个换行符
    'prefer-const': 0,                // 关闭对声明后从未重新赋值的变量,要常量声明
    'spaced-comment': 0,              // 关闭在注释中的//或/*后面强制使用一致的间距
    'no-multi-spaces': 0,              // 关闭不允许多个空格的检查
    'import/no-duplicates': 0,       // 解决vue组件重复导入问题
    indent: 0, // 解决js缩进问题
    'vue/multi-word-component-names': 0, // 解决组件名称单单词的问题
    'vue/no-unused-components': 0 //组件导入未使用问题
  }
}

运行启动

终端执行: npm run dev (其实就是使用vite 来启动,再package.json中还可以把dev 改成其他值,比如改成serve) ,那就还是npm run serve

然后就能浏览器访问页面了、

看src中的main.js文件, 引入的主文件, http://localhost:5173/ 访问的就是主文件。

接下来就是修改红框里的代码。来进行巩固学习。

1、入门知识

1. 这个看js的一些用法

http://localhost:5173/ 访问后,打开F12观察控制台

知识点都写在了 Study1.vue里面,就不介绍了

javascript 复制代码
// import App from './App.vue'
import App from './components/study/Study1.vue'

2. 这个是vue中的插值表达式{{}}

因为已经装了一些插件,如果是重新开始写代码,直接vbase, 选中其中一个模板,就可以快速生成代码,笔记已经写好了,直接用,知道就行。

不同变量的一些取值简单使用

javascript 复制代码
// import App from './App.vue'
import App from './components/study/Study2.vue'

3. v-text 和 v-html

效果和插值表达式差不多, v-text="" 中间可以放一些js语句,如 num +100

javascript 复制代码
import App from './components/study/Study3.vue'

4.v-bind, 简写 :

javascript 复制代码
import App from './components/study/Study4.vue'

属性前写了 v-bind: 或 : 后面就接变量

:class属性,后面的变量可以是字符串,可以是数组(推荐),也可以是对象

:style属性,后面可以字符串,数组, 字典对象(推荐)

a标签的,href属性能用, button标签的 disabled属性都可以使用

除此之外,引号中,是可以写js语句的,比如

javascript 复制代码
<div :style="{ color: 颜色变量名, 'font-size': 数值变量 + 'px' }">

5.v-if 和 v-show

注:v-if 和 v-else-if 和 v-else 是一组

javascript 复制代码
import App from './components/study/Study5.vue'

6.v-for 可以变出多个标签

javascript 复制代码
import App from './components/study/Study6a.vue' 

v-for = "" 引号中的写法 是 (item, index) in list, 当前标签就可以变成多个

  • 可以遍历数组(item,index) in list
  • 可以变量对象 (value, key, index) in person , 代码没举例

注:对于li标签,需要 :key="index" (是为了帮助 Vue 识别每个循环的元素,以便在数据更新时进行高效的重新渲染)

Study6a 和 Study6b的区别:

6a是 :key="index" , 6b是:key="item.id", 62更优秀,因为加值后,id 也不会变来变去

7. 操作动作属性 v-on 简写 @

javascript 复制代码
import App from './components/study/Study7.vue' 

v-on 写在有动作的标签里面,如<button></button>中

  • 可以放js代码,比如点了按钮就会执行
  • 可以触发函数,<button @click="addnum()">按钮</button>
  • 动作属性后面加.once, 如 <button v-on:click.once="count += 1">按钮</button> ,表示只会生效一次

接受参数 (能接受 事件对象)

1.定义事件与函数<input type="text" @input="input($event)" /> 也可以不打括号,函数就能默认接收到 事件对象

2.定义函数 const input = (e) => {console.log(e.target.value)} # e.target.value 表示该事件的对象的值 a.如是点击一个按钮, e.target 表示 该按钮标签 。

8. v-on 补充

  • @动作.once 一次
  • @动作.prevent
    • @click.prevent -----比如a标签的点击,会调整,可以prevent然后就不跳转,(也可以不加.prevent , 后面自定义函数,函数中要有,event.preventDefault()------Study8.vue
    • @submit.prevent 表单标签中加了这个,就不会刷新了
      • 我们使用 @submit.prevent 来监听表单的提交事件,并且使用 prevent 修饰符来阻止表单的默认提交行为。这样,当用户点击提交按钮时,不会触发表单的默认提交行为(即刷新),而是会执行我们自定义的 submitForm 方法。
      • 其实是 事件 event调用了e.preventDefault()
  • @动作.stop ,应该可以连起来用,没试过 .once.stop.prevent
  • 补充:input的键盘事件 - @keyup.enter=showMessge (键盘的回车事件)

9. v-on补充2.stop用在动作传递中起阻止传作用

  • @click.stop 停止(传递) (默认情况:如有多层,我点击内圈,相当于大的外圈也被点击了)
    • 其实是 事件 event调用了e.stopPropagation() 例子--Study9.vue----,如果在方法里使用了stopPropagation(),那么每层都会阻止了,可以注释,打开查

10. v-model双向绑定

---Study10.vue-

方式1:

假如不知道这个知识,可以用 @ v-on 和 : v-bind 结合,有双向绑定的效果,如下

: value,表示value取下面, @input 后面的js 意思又是把下面 改成 标签的value

复制代码
<input type="text" :value="address" @input="address = $event.target.value" />
    {{ address }}

方式2

使用 v-model="xxxx" ,便可以直接双向绑定, 直接绑定就是input输入框的value值

v-model:value="name" 可以省略简写 v-model="name"

11. v-model 的修饰符

---Study11vue---

  • v-model.lazy 标移才把输入值,传到变量
  • v-model.number 只会把数字传到变量
  • v-model.trim 去两侧的空格

12. v-model用在单选框、各input项的value值要先定义

---Study12.vue---

单选type="radio" 和普通 input文本框不同的是, input的值是输入的,而单选框:

  • 每个value值,要先自己定义好(就像下来选项先有值)。 (再用 v-model = "变量")
  • 一组内每个input要同样的 v-model="变量"

13. v-model用在多选框、各input项的value值要先定义

---Study13.vue---

与单选框不同的是, v-model="xxx" , xxx需要是一个数组

14.v-model用在select下拉选框

---Study14.vue---

对于select标签。

  • 1.先定义,select中的option的 value的 值, (如果不定义,绑的就是文本值)
    1. select 标签中 写 v-model="xxx"

选中一项后, 绑定的值就是所选option的value

对于单选下拉框, xxx定义成 字符串

对于复选下拉框,xxx定义成 列表(数组)

2、 入门知识2

1. 计算属性变量

vue3中完整写法 :---Study15vue---

computed中间时一个对象

去获取customValue 值时, 就是调用的 get,获取到了xxxx

当某个函数中给 customValue 设置值时, 会调用其中的set方法

javascript 复制代码
    const customValue = computed({
      get() { return xxxx},
      set:()=> {},  //可以这么写 set(){}
    })

computed中间是一个函数时,那就默认为只读,及这个函数就是get的函数。---Study16.vue---

vue2中的写法,稍显复杂,但是也是要定义get 和set的方法。

vue2_计算属性.html , 直接右键open with live server 打开

如下的例子, 如果 全名:<input type="text" v-model="fullName">, 绑定fullName,

就可以实现写姓名和改全名, 写全名可以改姓名,

如果是绑定fullName2 , 那么只能实现get, 及只能写姓名和改全名

2. watch 侦听属性

---Study17.vue---

侦听对象,和处罚函数的位置。

最后一个对象,可以不写

  • immediate: true,表示初始化会调用watch中的 那个函数
  • deep: true, 暂未知效果

侦听对象可以是reactive对象,或者ref对象。 reactive里面的具体对象也可以侦听,但写发不同

---Study18.vue---

按钮都是改变值,然后他们会按箭头所示,来触发函数

其中: 侦听函数中的方法中,可以支持异步的东西。 如代码中,侦听到num变化,过了5秒后,又变成了900

对于侦听函数,可以有多个侦听对象。---Study19vue---

  • 侦听一个变量写法(深度) : watch(num, (newValue, oldValue) => {},{immediate:true, deep:true})
  • 侦听一组变量写法 : watch( [num1, num2] , (newValue, oldValue) => {}) 此时newValue 表示两个值

注:

  1. 对于监听对象是ref时,watch的第一个参数,监听对象写, 不要写num.value ,如笔记中,直接写 num就行

  2. 如果是监听reactive对象,监听对象不能写成 state.num , 可以试试写成 () => state.num (如代码中的监听state.hellonum时)

vue2的侦听属性写法 src\components\study\vue2_侦听属性.html

  • 复杂写法 wath:{ 监控对象名 :{handler(){xxx}, immediate:ture, deep:true}}
  • 简单写法 watch:{ 监控对象名(){ xxx } }

3. vue3新增的watchEffect函数

---Study20vue--- 由于写法简单,用法就简单了,大概不能获取到变化后的值和老值

4. 侦听和计算的区别:

计算: src\components\study\vue2_计算属性.html

侦听: src\components\study\vue_侦听与计算对比.html

侦听的对象,改变之后, 触发的函数里面可以加异步的东西。

如代码中: 修改了firstName, 2秒后才异步的设置了 全名

案例1:实现搜索框

  • 通过watch来实现---Study21.vue--- 逻辑:输入文本框,一变化,就侦听到, 把新填的值,进行判断,去过滤,赋值到定义好的 临时空数组 页面展示(新的临时数组)
  • 通过computed来实现---Study22.vue--- - 逻辑:输入文本框,一变化,就计算, 得到计算属性临时列表, 页面也展示这个临时列表。

案例2:实现搜索+升序降序

设置一个变量,不同的按钮,点击后来重设变量为不同的值,根据值来if判断, 实现升序,还是降序

  • 需要使用到 数组.sort() ,--原理看代码 src\components\study\Study23.vue
  • ------src\components\study\Study24.vue------- 代码里面用到了三目运算, 来实现是升序,还是降序

5. 生命周期函数

vue3的生命周期函数写法: src\components\study\Study25.vue

onUnmounted 的例子在后面看 ,搜索 路由导航 router-link 和 router.push()方式

注:代码里面的生命周期函数是 vue3里面的,写在setup里面的,如果要用vue2的写法,写在和setup同级。

补充:

onMounted 执行完,刷新一下,才会渲染出页面 , 看 src\components\study\Study26.vue

补充案例,它里面一直在执行 onMounted的回调函数, 看src\components\study\Study27.vue

3.入门知识3:父子组件

假如xxx2.vue里有xxx1.vue, 我们就说xxx2.vue为父组件。

1. 数据---父给子

-----src\components\study2\Father.vue----------注意main.js中注意路径对不对--------

效果如下:

父vue中

  • 需要指定components, 表示可以用哪些 子vue, (即能用到哪些子vue标签)
  • 子组件标签中,可自定义属性,把变量 传给子组件
    • 如果不用 v-bind , 如下图 taoke="111" 就是传的字符串, 下图用了v-bind , :taoke="111" , 传过去的是number

子组件中:

用props来接收

方法1:

javascript 复制代码
  props: ['abc', 'age', 'hij'],

方式2-定义了数据格式:

javascript 复制代码
props: { abc: String, age: Number, hij: Array },

方式3:放松2的基础上还可以这样写,就还能定义默认值

javascript 复制代码
props: {
    abc: String,
    age: Number,
    hij: Array,
    taoke: {
      type: String,
    //   required: true,
      default: '如果父没有传,就用我'
    }
  }

注: 子组件中,父给子的 props的值,不能直接更改,,可以的做法就是, 先把 props的值,取到放到data中

2. 数据- 子给父

方式1 子组件中emit的方式

src\components\study2\Father2.vue 效果如下

父vue中

  • 用 components ,包含哪些组件。
  • 在子组件标签中,用v-on绑定一个自定义属性 = 函数 (可以接受子组件 emit传过来的参数)。

子vue中(Child2.vue)

  • 使用emit('自定义属性', state) ,这样就能把state传给父中的函数,并能接收一个参数

方式2: 子组件中,定义props.onMounted中给props给值

子:

要定义props, onMounted中给props给值 (setup要写成 setup(props){} )

父中:

子组件标签中使用abc属性, 后面接函数 () (函数可以接受一个参数,该参数就是abc传来的值)

方式3(和1 差不多。还要多经过一层)

子中: 是一样的, 用emit 来发射

父中:子组件标签中, 写一个 ref= "child" , 然后用如图的写法

3. 父组件中,使用component标签来放子组件

src\components\study2\Father4.vue

4 . 插槽

插槽允许父组件在使用子组件时向子组件传递额外的内容,以便在子组件的特定位置插入这些内容。

根据现象可以观察,无名插槽会挤在一起, 展示顺序要看 子组件中 各个 slot的位置

无名插槽

src\components\study3\Father.vue

  • 子组件中,使用 <slot> 标签来标记一个插槽位置:
  • 父组件中,在子组件标签内插入内容来填充插槽。这些内容将会被传递到子组件中对应的 <slot>标签位置

有名插槽

src\components\study3\Father2.vue

使用具名插槽(有名插槽)来更灵活地在父组件中向子组件传递内容。

具名插槽允许你在子组件中定义多个插槽位置,并在父组件中选择要填充的插槽。这对于需要在不同位置插入不同内容的情况非常有用。

  • 子中,slot 标签要指定一个 name
  • 父中,使用template标签,并用v-slot指定 插槽名字, 或者用简写 #插槽名字

子组件里可以用在插槽位置 slot标签 把子组件的数据传给 父组件 。

src\components\study3\Father3.vue

那个tmplist命名是自己随便命的

4. 入门4、跨组件通信

实际业务情况常常为,一个公共组件,比 列表组件,它们里面多为inject, 当具体的一个业务列表时, 就会provide对应业务的数据

如下图分别是

src\components\study3\One1.vue 使用了公共组件作为子组件

src\components\study3\One.vue 使用了公共组件作为子组件

补充:

可以provide reactive的一项(上面的例子)

可以provide 整个reactive对象

也可以provide 一个 ref 对象

三、vue框架

1. 路由配置基础

原本:一个路由关联一个vue组件, 当访问的路由时,组件内容会去替换<router-view> 或者另写法 <RouterView />

以上知识点:

路由模式 即history属性有两种

  • createWebHashHistory, 项目路径要加 路由前面要加 /#
  • createWebHistory

两种方式:

复制代码
// which is lazy-loaded when the route is visited.(访问路由,才加载这个组件 ,懒加载)

特点: 项目打包时,一个组件打包成一个js文件

    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')

npm i vue-router, 可以看下packagege.json中有没有安装 npm i vue-router@next --save

  1. 总组件中(要改main.js中的那个组件) 改成 import App from './App2.vue', 简介一点
  2. 配置新的url, 路由---组件 (router文件 中 index.js), /test路由中选一个 vue文件

路由配置是如何生效的, 是由于有main.js文件,里面使用到了配置。

总组件中(路由为/ 的),可以写访问 子路由的东西, 访问子路由后,对应的组件展示在位置。

2.路由重定向配置

准备工作:

main.js中,import App from './components/luyou/test1.vue'

然后点击他们都可以实现路由的跳转

方式1:使用 router-link ,跳转 (申明式) 方式2:是方法中使用router.push('/about1')

  • to表示路由, to后面的值 和 router index.js中的 path 一样, 如下有两种方式
javascript 复制代码
// 写法1
<router-link to="/about1" active-class="active">about</router-link>
// 写法2 (这样写,就可以用path 或者用name了)
<router-link :to="{ path: '/home1' }" active-class="active">首页ya</router-link>
  • active-class 表示 选中后的样式,如下active,就写到style里面, 比如代码里是写的红色
补充:不展示的路由的组件,它就失效了

时效了,就会触发生命周期函数的

setup中的onBeforeUnmount 和onUnmounted 方法 (vue3)

或者和setup同级的 unmounted 方法 (vue2)

让不展示的路由组件保持挂载在页面,不被摧毁 (拥有缓存)

作用:防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。

做法:在饮用子组件的的外层添加了 标签

src\components\luyou\test1.vue 中 没有生效,不知道为什么,如果成功,

参数:

  • include ="子组件的名称" 子组件的名称定义写在,和setup同级,写name="xxx",如下图,就可以针对性,对某个组件进行缓存
  • 如果需要限制缓存的组件数量,你可以使用 max 属性进行设置,如 <keep-alive max="3">

4. 路由的前进后退

vue3

javascript 复制代码
script中
import { useRouter } from 'vue-router'

或者   import router from '@/router'   // 项目文件中自己定义的(不要中括号) ,下面就不用const  router了
---------------setup中
const router = useRouter()



router.forward()    # 前进
router.back()       # 后退 
router.go()        # 传-1,就是后退一下,-2是两下, 1是前进,  不传没效果

vue2

javascript 复制代码
不是setup的
this.$router.forward()
this.$router.back()
this.$router.go(1)

5.嵌套路由(二级路由)

访问/kengcheng路由时, 访问kecheng.vue时,的css样式,需要装一个插件 npm install -D less

这里我们看出,那个Back.vue的内容,后端内容列表就放出来。过程是下图这个样子

main.js中,还是用import App from './components/luyou/test1.vue' 作为主组件,

点击传参到kekeng1,路由,对应组件是 src\components\luyou\Kecheng2.vue

使用this.$route.query 获取时,及格式为 路由?name=xxx&age=yyy的格式

传参方式1:

点击前端,进行查看

/about1/front?text2=小滴课堂yaya

多参数/about1/front?text2=小滴课堂yaya & address=xxxx


传参方式2-实现效果和上面一样也是url传参:

点击后端,进行查看

router-link 里面的to参数 里面放一个字典, 里面有个query, 再放参数对象

使用this.$route.params获取时,效果是把参数直接拼到路由

方式1: 点击params传参, 进行查看

三个地方:

  1. 路由配置,把参数配置成路由中。

2 router-link处

  1. 获取要这样写

方式2,

和方式1,不同的是 to后面接对象,且带一个params对象

router-link的replace的意思
  1. 看 这, 有了他效果就是,点击其他也没,再到这里, 后退就后退不过去了, 点击后退,或者点击浏览的返回都退不去了

7.编程式导航

看src\components\luyou\test1.vue

this.$router.push('/home1')

javascript 复制代码
//vue3
import { useRouter } from 'vue-router'
const router = useRouter()            // 这个也写在setup里面

或者  import router from '@/router'   // 项目文件中自己定义的(不要中括号)
方法中写这个:router.push('/about1')

//vue2的写法
this.$router.push('/home1')
   

传参:

路由配置一下, 也可以像6中 的prarams传参一样

javascript 复制代码
//多参数的传递
this.$router.push('/home1/taoke/18')        // 需要配置好路由为  path:/home1/:name/:age


// 也可以用对象的形式 (和下方的 params传参的对象,一样的传递方式)
this.$router.push(  { name: 'ceshi', params: { text: name } })     

// 待跳转的组件获取值,也和下面的  parms传参一样
mounted() {
    console.log(this.$route.params) // {myName: "直接拼在后面"}
  }

this.$router.replace('/home1')

如果是这种,相比方式2, 它会跳转,并且会替换上一个路由记录,返回就不会一层一层返回

8.路由守卫

  1. 组件的路由进行配置
  1. 看下面这部分代码,是要放到路由的index.js中的,

如果加上这部分代码后, 每个页面都不能访问,要自己回到 / login

javascript 复制代码
router.beforeEach((to, from, next) => {

  const userId = localStorage.getItem('userId')
  // eslint-disable-next-line no-cond-assign
  if (to.path === '/login') {
    next()
  } else if (userId) {
    next()
  } else {
  next('/login')
  }


}

)
  1. 换个判断逻辑,路由配置里的额外信息判断,某些也没再校验是否登录
javascript 复制代码
router.beforeEach((to, from, next) => {

  const userId = localStorage.getItem('userId')
  // eslint-disable-next-line no-cond-assign
  if (to.meta.needAuth ) {
    if (userId) {
      next()
    } else { 
      next('/login')
      alert('请登录')
    }
  } 
  else {
    next()
 
  }
}
)

模拟登录

相关推荐
百万蹄蹄向前冲35 分钟前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5811 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路1 小时前
GeoTools 读取影像元数据
前端
ssshooter2 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友2 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry3 小时前
Jetpack Compose 中的状态
前端
dae bal3 小时前
关于RSA和AES加密
前端·vue.js
柳杉3 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog4 小时前
低端设备加载webp ANR
前端·算法
LKAI.4 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi