2024-08-08



<template>
  <el-form :model="form" :rules="rules" ref="loginForm">
    <el-form-item prop="username">
      <el-input v-model="form.username" placeholder="Username"></el-input>
    </el-form-item>
    <el-form-item prop="password">
      <el-input type="password" v-model="form.password" placeholder="Password"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('loginForm')">Login</el-button>
      <el-button @click="resetForm('loginForm')">Reset</el-button>
    </el-form-item>
  </el-form>
</template>
 
<script setup>
import { reactive, ref } from 'vue';
import { ElMessage } from 'element-plus';
 
const form = reactive({
  username: '',
  password: ''
});
 
const loginForm = ref(null);
 
const validateUsername = (rule, value, callback) => {
  if (value.length < 6) {
    callback(new Error('Username must be at least 6 characters long'));
  } else {
    callback();
  }
};
 
const validatePassword = (rule, value, callback) => {
  if (value.length < 6) {
    callback(new Error('Password must be at least 6 characters long'));
  } else {
    callback();
  }
};
 
const rules = {
  username: [
    { required: true, message: 'Please input username', trigger: 'blur' },
    { validator: validateUsername, trigger: 'blur' }
  ],
  password: [
    { required: true, message: 'Please input password', trigger: 'blur' },
    { validator: validatePassword, trigger: 'blur' }
  ]
};
 
const submitForm = (formName) => {
  loginForm.value.validate((valid) => {
    if (valid) {
      ElMessage.success('Login Success');
      // 实际项目中这里会调用登录API
    } else {
      ElMessage.error('Login Fail');
      return false;
    }
  });
};
 
const resetForm = (formName) => {
  loginForm.value.resetFields();
};
</script>

这个代码实例展示了如何在Vue 3中使用Element Plus的el-form组件来创建一个登录表单,并使用表单验证规则。它包括了用户名和密码的验证,以及登录和重置表单的方法。这个例子简洁明了,并且提供了一个很好的表单验证实践。

2024-08-08

在前端开发中,Vue.js和React.js是两大主流框架。以下是它们的一些深度对比:

  1. 学习曲线:

    React通常需要更多的学习曲线,包括JSX、状态管理和虚拟DOM。Vue则提供更直观的模板和框架设计。

  2. 状态管理:

    React更倾向于使用外部库(如Redux)来管理状态,而Vue则提供了一个更简单的状态管理系统(Vuex)。

  3. 生态系统:

    React有一个更庞大和更分散的生态系统,包括诸如Relay、GraphQL等高级特性。Vue的社区提供了如Vue CLI、Vuex、Vue Router等官方解决方案。

  4. 性能:

    在React中,组件的重新渲染是基于shouldComponentUpdate生命周期钩子。而在Vue中,使用了更高效的依赖追踪和虚拟DOM的patching算法。

  5. 类型检查:

    React与TypeScript结合使用可以提供强大的类型检查,而Vue可以通过Vetur插件进行Vue特定的类型检查。

  6. 学习资源:

    React有大量的官方文档和社区资源,而Vue的中文文档比较完善,但对于初学者可能不够丰富。

  7. 社区活跃度:

    两者的社区都非常活跃,但在某些情况下,React的库可能会有更活跃的更新节奏。

  8. 选择:

    选择哪个框架通常取决于项目需求、团队技术栈和个人偏好。对于想要更多控制权和更简单的学习曲线的开发者,Vue可能是更好的选择。而对于需要构建大型应用和复杂UI的开发者,React可能是更好的选择。

以下是一个简单的React和Vue组件的对比:

React (使用JSX):




import React, { useState } from 'react';
 
const App = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Vue:




<template>
  <div>
    <p>You clicked {{ count }} times</p>
    <button @click="increment">
      Click me
    </button>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count += 1;
    },
  },
};
</script>

两者都创建了一个有状态的计数器组件,但是React使用了JSX和Hooks,而Vue使用了模板和methods函数。这两种风格各有优缺点,最终选择取决于项目需求和团队偏好。

2024-08-08



<template>
  <div>
    <h1>{{ msg }}</h1>
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
// 声明响应式数据
const msg = ref('Hello Vue 3!')
</script>
 
<style scoped>
h1 {
  color: #333;
}
</style>

这个例子展示了如何在Vue 3和Vite环境中创建一个简单的组件。它使用了<script setup>语法糖,这是Vue 3中的一个新特性,可以让你更直观地使用组合式API。同时,它还演示了如何使用ref来创建响应式数据,这是Vue 3中用于响应式的基本概念之一。

2024-08-08



<template>
  <div class="ocr-text-box" :style="style">
    <div class="ocr-text" @click="copyText">
      {{ text }}
    </div>
  </div>
</template>
 
<script>
export default {
  props: {
    text: String,
    boundingBox: Object,
  },
  computed: {
    style() {
      const { top, left, width, height } = this.boundingBox;
      return {
        top: `${top}px`,
        left: `${left}px`,
        width: `${width}px`,
        height: `${height}px`,
      };
    },
  },
  methods: {
    copyText() {
      navigator.clipboard.writeText(this.text).then(
        () => console.log('Text copied to clipboard'),
        (error) => console.error('Failed to copy text:', error)
      );
    },
  },
};
</script>
 
<style scoped>
.ocr-text-box {
  position: absolute;
  background-color: rgba(255, 255, 255, 0.7);
  border: 1px solid #333;
  box-sizing: border-box;
  pointer-events: none;
}
 
.ocr-text {
  user-select: text;
  cursor: text;
}
</style>

这个Vue组件接收两个props:textboundingBoxboundingBox 对象包含 OCR 识别文本框的位置和尺寸信息。计算属性 style 将这些信息转换成CSS样式,用于定位文本框。方法 copyText 使用浏览器的剪贴板API将文本复制到剪贴板,允许用户直接粘贴文本。该组件使用了 pointer-events: none 来防止文本框本身影响图片的交互,并使用了 user-select: textcursor: text 来提供更好的文本选中和复制体验。

2024-08-08



<template>
  <div class="live-danmaku-container">
    <vue-virtual-scroller
      :items="danmakuList"
      :item-height="30"
      :remain="7"
      @update="scrollToBottom"
    >
      <template v-slot:default="{ item }">
        <div class="live-danmaku-item">{{ item.text }}</div>
      </template>
    </vue-virtual-scroller>
  </div>
</template>
 
<script>
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
 
export default {
  components: {
    VueVirtualScroller
  },
  data() {
    return {
      danmakuList: [] // 假设这里是一个长达弹幕列表数据
    }
  },
  methods: {
    scrollToBottom(startIndex) {
      // 滚动到列表底部
      this.$nextTick(() => {
        const container = this.$el.querySelector('.live-danmaku-container')
        container.scrollTop = container.scrollHeight
      })
    },
    addDanmaku(danmaku) {
      // 添加新弹幕,并保持列表在底部
      this.danmakuList.push(danmaku)
    }
  }
}
</script>
 
<style scoped>
.live-danmaku-container {
  height: 150px; /* 设置合适的高度 */
  overflow-y: auto;
  position: relative;
}
.live-danmaku-item {
  height: 30px; /* 设置每个弹幕项的高度 */
}
</style>

这个代码实例展示了如何在Vue 3项目中使用vue-virtual-scroller组件来优化长列表的渲染性能。通过设置合适的高度和每个列表项的高度,可以确保在有大量数据的情况下也能高效地进行滚动。scrollToBottom方法确保了在数据更新时列表能自动滚动到底部,提供了更好的用户体验。

2024-08-08

在Vue中,可以通过自定义指令来实现长按事件。以下是一个简单的自定义指令示例,它可以在H5和PC端工作:




// 注册一个全局自定义指令 `v-longpress`
Vue.directive('longpress', {
  bind: function (el, binding, vNode) {
    // 确保提供的表达式是函数
    if (typeof binding.value !== 'function') {
      // 获取组件名称
      const compName = vNode.context.name;
      let warn = `[longpress:] provided expression '${binding.expression}' is not a function, but has to be`;
      if (compName) { warn += `Found in component '${compName}'`; }
      console.warn(warn);
    }
    // 定义变量
    let pressTimer = null;
    // 创建计时器( 1秒后执行函数 )
    let start = (e) => {
      if (e.type === 'click' && e.button !== 0) {
        return;
      }
      if (pressTimer === null) {
        pressTimer = setTimeout(() => {
          // 执行函数
          handler(e);
        }, 1000);
      }
    }
    // 取消计时器
    let cancel = () => {
      if (pressTimer !== null) {
        clearTimeout(pressTimer);
        pressTimer = null;
      }
    }
    // 运行函数
    const handler = (e) => {
      binding.value(e);
    }
    // 添加事件监听器
    el.addEventListener('mousedown', start);
    el.addEventListener('touchstart', start);
    // 取消计时器
    el.addEventListener('click', cancel);
    el.addEventListener('mouseout', cancel);
    el.addEventListener('touchend', cancel);
    el.addEventListener('touchcancel', cancel);
  }
});

在你的Vue组件中,可以这样使用这个自定义指令:




<template>
  <div v-longpress="longPressHandler">长按我</div>
</template>
 
<script>
export default {
  methods: {
    longPressHandler() {
      // 处理长按事件
      console.log('长按事件触发了!');
    }
  }
}
</script>

这个自定义指令v-longpress可以绑定一个函数,在长按事件发生时执行这个函数。它通过监听mousedowntouchstart事件来开始计时,如果在1秒内发生了click或者其他鼠标事件,则取消计时器;如果1秒钟内没有其他事件发生,则执行绑定的函数。

2024-08-08



<template>
  <div class="map-container">
    <el-amap class="map" :vid="'amap'" :zoom="10">
      <el-amap-marker v-for="(marker, index) in markers" :key="index" :position="marker"></el-amap-marker>
    </el-amap>
    <div class="search-box">
      <input v-model="searchKey" @keyup.enter="searchLocation" type="text" placeholder="请输入搜索文字">
      <button @click="searchLocation">搜索</button>
    </div>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      searchKey: '',
      markers: [],
      map: null,
    };
  },
  methods: {
    searchLocation() {
      const that = this;
      this.map.plugin('AMap.Geolocation', function() {
        let geolocation = new AMap.Geolocation({
          enableHighAccuracy: true, // 是否使用高精度定位,默认:true
          timeout: 10000,          // 超过10秒后停止定位,默认:5s
        });
        geolocation.getCurrentPosition();
        AMap.event.addListener(geolocation, 'complete', onComplete); // 返回定位信息
        AMap.event.addListener(geolocation, 'error', onError);      // 返回定位出错信息
        function onComplete(data) {
          // data是一个对象,内含经纬度信息
          that.markers.push([data.position.getLng(), data.position.getLat()]);
        }
        function onError(data) {
          // 定位出错
          console.log('定位失败', data);
        }
      });
    },
  },
  mounted() {
    this.map = this.$refs.amap.$map;
  },
};
</script>
 
<style>
.map-container {
  position: relative;
  height: 400px;
}
.map {
  height: 100%;
}
.search-box {
  position: absolute;
  top: 10px;
  left: 10px;
}
.search-box input {
  padding: 8px;
  border-radius: 4px;
  border: 1px solid #ccc;
  outline: none;
}
.search-box button {
  padding: 8px 12px;
  border: 1px solid #1a73e8;
  background-color: #1a73e8;
  color: white;
  border-radius: 4px;
  cursor: pointer;
}
</style>

这段代码实现了在Vue中使用高德地图的基本功能:搜索位置并在地图上标记点,同时点击标记点可以弹窗显示位置详情。代码中使用了Element UI的<el-input><el-button>组件来简化表单和按钮的创建过程。

2024-08-08



<template>
  <div ref="boxRef" class="box">
    <!-- 内容 -->
  </div>
</template>
 
<script setup>
import { ref, onMounted } from 'vue';
 
const boxRef = ref(null);
const boxRect = ref(null);
 
onMounted(() => {
  if (boxRef.value) {
    boxRect.value = boxRef.value.getBoundingClientRect();
    // 执行需要的操作,例如使用boxRect.value的数据
  }
});
</script>
 
<style>
.box {
  /* 样式 */
}
</style>

这段代码使用了Vue 3的Composition API(setup函数)来获取DOM元素的尺寸和相对于视口的位置。它首先定义了一个ref变量boxRef来引用DOM元素,然后在onMounted生命周期钩子中,通过访问boxRef.value.getBoundingClientRect()获取元素的布局信息,并将结果存储在boxRect.value中。这样就可以在组件挂载后获取并使用元素的尺寸信息。

2024-08-08

在将Vue项目迁移到内网环境时,你需要确保所有的依赖项都可以在内网中获取。以下是迁移的步骤:

  1. 复制项目代码到内网机器。
  2. 在内网环境中创建一个新的pnpm-workspace.yaml文件(如果项目是一个工作空间)。
  3. 使用pnpm install安装所有依赖。
  4. 如果内网环境无法访问外部仓库,可以使用pnpm store设置一个内网的存储位置,并将所有依赖项从外部仓库复制到这个存储位置。
  5. 修改项目配置,如vue.config.js,确保所有的资源路径正确。
  6. 构建项目,运行pnpm run build
  7. 如果有必要,修改package.json中的脚本,确保使用pnpm而不是npm
  8. 在内网服务器上部署构建产物。

注意:如果内网环境中所有机器都无法访问外部npm仓库,你可能需要在内网环境中搭建一个npm私服(如Verdaccio),然后将所有依赖项发布到这个私服上。

示例代码:




# 安装pnpm
npm install -g pnpm
 
# 复制项目到内网机器
scp -r my-vue-app user@internal-network-machine:/path/to/directory
 
# 在内网机器上
cd /path/to/directory/my-vue-app
 
# 安装依赖
pnpm install
 
# 修改vue.config.js(如果需要)
# 修改package.json中的脚本(如果需要)
 
# 构建项目
pnpm run build
 
# 部署构建产物到服务器
# 通常这涉及到将dist目录的内容复制到服务器的web目录
2024-08-08



import { mount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
 
// 使用Jest测试简单的Vue 3组件
describe('MyComponent', () => {
  it('显示默认的问候', () => {
    // 挂载组件
    const wrapper = mount(MyComponent);
 
    // 断言:组件的根元素包含正确的文本
    expect(wrapper.text()).toContain('Hello, Vue Test Utils!');
  });
 
  it('可以更改问候语', () => {
    // 挂载组件,并传入props
    const wrapper = mount(MyComponent, {
      props: { greeting: 'Hello, Jest!' }
    });
 
    // 断言:组件的根元素包含更新后的文本
    expect(wrapper.text()).toContain('Hello, Jest!');
  });
});

这个例子展示了如何使用@vue/test-utils和Jest来测试一个简单的Vue 3组件。它演示了如何挂载组件,并通过传递props来测试组件的不同状态。最后,它使用了expect和Jest的toContain方法来进行断言,确保组件的行为符合我们的预期。