JavaScript语法总结
概述
JavaScript是一种动态的、弱类型的编程语言,广泛用于Web开发。在Markdown文档中,JavaScript可以通过多种方式嵌入和使用。
在Markdown中嵌入JavaScript
1. 代码块展示
markdown
```javascript
// 基础JavaScript代码
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("World"));
```2. HTML中的JavaScript
html
<script>
// 直接在HTML中嵌入JavaScript
document.addEventListener('DOMContentLoaded', function() {
console.log('页面加载完成');
});
</script>3. 内联事件处理
html
<button onclick="alert('按钮被点击了!')">点击我</button>
<div onmouseover="this.style.color='red'" onmouseout="this.style.color='black'">
鼠标悬停变色
</div>4. 在Markdown中嵌入视频
基础HTML5视频
html
<!-- 本地视频文件 -->
<video width="640" height="360" controls>
<source src="./videos/demo.mp4" type="video/mp4">
<source src="./videos/demo.webm" type="video/webm">
<source src="./videos/demo.ogg" type="video/ogg">
您的浏览器不支持视频标签。
</video>
<!-- 带有更多属性的视频 -->
<video
width="100%"
height="auto"
controls
autoplay
muted
loop
poster="./images/video-poster.jpg"
preload="metadata">
<source src="./videos/demo.mp4" type="video/mp4">
<track kind="subtitles" src="./subtitles/demo-zh.vtt" srclang="zh" label="中文字幕">
<track kind="subtitles" src="./subtitles/demo-en.vtt" srclang="en" label="English">
</video>响应式视频容器
html
<!-- 响应式视频包装器 -->
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
<video
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
controls>
<source src="./videos/demo.mp4" type="video/mp4">
</video>
</div>嵌入在线视频平台
html
<!-- YouTube视频 -->
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/VIDEO_ID"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
<!-- 哔哩哔哩视频 -->
<iframe
width="560"
height="315"
src="//player.bilibili.com/player.html?bvid=BV_ID&page=1"
scrolling="no"
border="0"
frameborder="no"
framespacing="0"
allowfullscreen="true">
</iframe>
<!-- 响应式iframe -->
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
<iframe
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
src="https://www.youtube.com/embed/VIDEO_ID"
frameborder="0"
allowfullscreen>
</iframe>
</div>JavaScript控制视频播放
html
<video id="myVideo" width="640" height="360" controls>
<source src="./videos/demo.mp4" type="video/mp4">
</video>
<div style="margin-top: 10px;">
<button onclick="playVideo()">播放</button>
<button onclick="pauseVideo()">暂停</button>
<button onclick="changeVolume(0.5)">音量50%</button>
<button onclick="skipTo(30)">跳转到30秒</button>
<button onclick="changeSpeed(1.5)">1.5倍速</button>
</div>
<script>
const video = document.getElementById('myVideo');
function playVideo() {
video.play();
}
function pauseVideo() {
video.pause();
}
function changeVolume(volume) {
video.volume = volume;
}
function skipTo(seconds) {
video.currentTime = seconds;
}
function changeSpeed(speed) {
video.playbackRate = speed;
}
// 监听视频事件
video.addEventListener('loadstart', () => console.log('开始加载'));
video.addEventListener('canplay', () => console.log('可以播放'));
video.addEventListener('play', () => console.log('开始播放'));
video.addEventListener('pause', () => console.log('暂停播放'));
video.addEventListener('ended', () => console.log('播放结束'));
</script>自定义视频播放器
html
<div class="custom-video-player">
<video id="customVideo" width="640" height="360">
<source src="./videos/demo.mp4" type="video/mp4">
</video>
<div class="video-controls">
<button id="playPauseBtn">▶️</button>
<input type="range" id="progressBar" min="0" max="100" value="0">
<span id="timeDisplay">00:00 / 00:00</span>
<input type="range" id="volumeBar" min="0" max="1" step="0.1" value="1">
<button id="fullscreenBtn">⛶</button>
</div>
</div>
<style>
.custom-video-player {
position: relative;
display: inline-block;
}
.video-controls {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
background: #333;
color: white;
}
.video-controls button {
background: none;
border: none;
color: white;
cursor: pointer;
font-size: 16px;
}
.video-controls input[type="range"] {
flex: 1;
}
#progressBar {
min-width: 200px;
}
#volumeBar {
width: 80px;
}
</style>
<script>
const customVideo = document.getElementById('customVideo');
const playPauseBtn = document.getElementById('playPauseBtn');
const progressBar = document.getElementById('progressBar');
const timeDisplay = document.getElementById('timeDisplay');
const volumeBar = document.getElementById('volumeBar');
const fullscreenBtn = document.getElementById('fullscreenBtn');
// 播放/暂停切换
playPauseBtn.addEventListener('click', () => {
if (customVideo.paused) {
customVideo.play();
playPauseBtn.textContent = '⏸️';
} else {
customVideo.pause();
playPauseBtn.textContent = '▶️';
}
});
// 进度条更新
customVideo.addEventListener('timeupdate', () => {
const progress = (customVideo.currentTime / customVideo.duration) * 100;
progressBar.value = progress;
const current = formatTime(customVideo.currentTime);
const duration = formatTime(customVideo.duration);
timeDisplay.textContent = `${current} / ${duration}`;
});
// 进度条拖拽
progressBar.addEventListener('input', () => {
const time = (progressBar.value / 100) * customVideo.duration;
customVideo.currentTime = time;
});
// 音量控制
volumeBar.addEventListener('input', () => {
customVideo.volume = volumeBar.value;
});
// 全屏切换
fullscreenBtn.addEventListener('click', () => {
if (customVideo.requestFullscreen) {
customVideo.requestFullscreen();
}
});
// 时间格式化
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
</script>视频懒加载
html
<!-- 使用Intersection Observer实现视频懒加载 -->
<video
class="lazy-video"
width="640"
height="360"
controls
preload="none"
data-src="./videos/demo.mp4"
poster="./images/video-poster.jpg">
<source data-src="./videos/demo.mp4" type="video/mp4">
</video>
<script>
// 视频懒加载实现
const lazyVideos = document.querySelectorAll('.lazy-video');
const videoObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const video = entry.target;
const source = video.querySelector('source');
// 设置视频源
if (video.dataset.src) {
video.src = video.dataset.src;
video.load();
}
if (source && source.dataset.src) {
source.src = source.dataset.src;
video.load();
}
// 移除观察
videoObserver.unobserve(video);
video.classList.remove('lazy-video');
}
});
});
lazyVideos.forEach(video => {
videoObserver.observe(video);
});
</script>视频播放列表
html
<div class="video-playlist">
<video id="playlistVideo" width="640" height="360" controls>
<source src="" type="video/mp4">
</video>
<div class="playlist">
<div class="playlist-item active" data-src="./videos/video1.mp4">
<img src="./images/thumb1.jpg" alt="视频1">
<span>第一集:介绍</span>
</div>
<div class="playlist-item" data-src="./videos/video2.mp4">
<img src="./images/thumb2.jpg" alt="视频2">
<span>第二集:基础</span>
</div>
<div class="playlist-item" data-src="./videos/video3.mp4">
<img src="./images/thumb3.jpg" alt="视频3">
<span>第三集:进阶</span>
</div>
</div>
</div>
<style>
.video-playlist {
display: flex;
gap: 20px;
max-width: 1000px;
}
.playlist {
width: 300px;
}
.playlist-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
cursor: pointer;
border: 2px solid transparent;
border-radius: 8px;
margin-bottom: 10px;
}
.playlist-item:hover {
background: #f5f5f5;
}
.playlist-item.active {
border-color: #007acc;
background: #e3f2fd;
}
.playlist-item img {
width: 60px;
height: 40px;
object-fit: cover;
border-radius: 4px;
}
</style>
<script>
const playlistVideo = document.getElementById('playlistVideo');
const playlistItems = document.querySelectorAll('.playlist-item');
playlistItems.forEach(item => {
item.addEventListener('click', () => {
// 移除所有active类
playlistItems.forEach(i => i.classList.remove('active'));
// 添加active类到当前项
item.classList.add('active');
// 更换视频源
const videoSrc = item.dataset.src;
playlistVideo.src = videoSrc;
playlistVideo.load();
playlistVideo.play();
});
});
// 视频结束后自动播放下一个
playlistVideo.addEventListener('ended', () => {
const currentActive = document.querySelector('.playlist-item.active');
const nextItem = currentActive.nextElementSibling;
if (nextItem && nextItem.classList.contains('playlist-item')) {
nextItem.click();
}
});
</script>视频截图功能
html
<div class="video-capture">
<video id="captureVideo" width="640" height="360" controls>
<source src="./videos/demo.mp4" type="video/mp4">
</video>
<div class="capture-controls">
<button onclick="captureFrame()">📸 截图</button>
<button onclick="downloadCapture()">💾 下载截图</button>
</div>
<canvas id="captureCanvas" style="display: none;"></canvas>
<div id="capturePreview"></div>
</div>
<script>
const captureVideo = document.getElementById('captureVideo');
const captureCanvas = document.getElementById('captureCanvas');
const capturePreview = document.getElementById('capturePreview');
const ctx = captureCanvas.getContext('2d');
let currentCapture = null;
function captureFrame() {
// 设置canvas尺寸
captureCanvas.width = captureVideo.videoWidth;
captureCanvas.height = captureVideo.videoHeight;
// 绘制当前帧到canvas
ctx.drawImage(captureVideo, 0, 0);
// 转换为图片并显示预览
currentCapture = captureCanvas.toDataURL('image/png');
capturePreview.innerHTML = `
<h4>截图预览:</h4>
<img src="${currentCapture}" style="max-width: 300px; border: 1px solid #ddd;">
<p>时间点: ${formatTime(captureVideo.currentTime)}</p>
`;
}
function downloadCapture() {
if (!currentCapture) {
alert('请先截图');
return;
}
const link = document.createElement('a');
link.download = `video-capture-${Date.now()}.png`;
link.href = currentCapture;
link.click();
}
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
</script>视频弹幕系统
html
<div class="video-danmaku-container">
<video id="danmakuVideo" width="640" height="360" controls>
<source src="./videos/demo.mp4" type="video/mp4">
</video>
<div class="danmaku-overlay" id="danmakuOverlay"></div>
<div class="danmaku-input">
<input type="text" id="danmakuText" placeholder="输入弹幕内容">
<button onclick="sendDanmaku()">发送弹幕</button>
</div>
</div>
<style>
.video-danmaku-container {
position: relative;
display: inline-block;
}
.danmaku-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
.danmaku-item {
position: absolute;
color: white;
font-size: 16px;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
white-space: nowrap;
animation: danmaku-move 8s linear;
}
@keyframes danmaku-move {
from {
transform: translateX(100%);
}
to {
transform: translateX(-100%);
}
}
.danmaku-input {
margin-top: 10px;
display: flex;
gap: 10px;
}
.danmaku-input input {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.danmaku-input button {
padding: 8px 16px;
background: #007acc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
<script>
const danmakuVideo = document.getElementById('danmakuVideo');
const danmakuOverlay = document.getElementById('danmakuOverlay');
const danmakuText = document.getElementById('danmakuText');
// 预设弹幕数据
const danmakuData = [
{ time: 5, text: '开始了!', color: '#ff6b6b' },
{ time: 15, text: '这个很有趣', color: '#4ecdc4' },
{ time: 30, text: '学到了!', color: '#45b7d1' },
{ time: 45, text: '666', color: '#96ceb4' }
];
let currentDanmakuIndex = 0;
// 监听视频时间更新
danmakuVideo.addEventListener('timeupdate', () => {
const currentTime = danmakuVideo.currentTime;
// 检查是否有弹幕需要显示
while (currentDanmakuIndex < danmakuData.length &&
danmakuData[currentDanmakuIndex].time <= currentTime) {
showDanmaku(danmakuData[currentDanmakuIndex]);
currentDanmakuIndex++;
}
});
// 视频重新开始时重置弹幕索引
danmakuVideo.addEventListener('seeked', () => {
const currentTime = danmakuVideo.currentTime;
currentDanmakuIndex = danmakuData.findIndex(d => d.time > currentTime);
if (currentDanmakuIndex === -1) currentDanmakuIndex = danmakuData.length;
});
function showDanmaku(danmaku) {
const danmakuElement = document.createElement('div');
danmakuElement.className = 'danmaku-item';
danmakuElement.textContent = danmaku.text;
danmakuElement.style.color = danmaku.color || 'white';
danmakuElement.style.top = Math.random() * 80 + '%';
danmakuOverlay.appendChild(danmakuElement);
// 8秒后移除弹幕元素
setTimeout(() => {
if (danmakuElement.parentNode) {
danmakuElement.parentNode.removeChild(danmakuElement);
}
}, 8000);
}
function sendDanmaku() {
const text = danmakuText.value.trim();
if (!text) return;
const newDanmaku = {
time: danmakuVideo.currentTime,
text: text,
color: '#' + Math.floor(Math.random()*16777215).toString(16)
};
showDanmaku(newDanmaku);
danmakuText.value = '';
}
// 回车发送弹幕
danmakuText.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendDanmaku();
}
});
</script>JavaScript基础语法
变量声明
javascript
// ES6+ 推荐使用 let 和 const
let variable = "可变变量";
const constant = "常量";
var oldStyle = "旧式声明"; // 不推荐
// 数据类型
let number = 42;
let string = "字符串";
let boolean = true;
let array = [1, 2, 3];
let object = { key: "value" };
let nullValue = null;
let undefinedValue = undefined;函数定义
javascript
// 函数声明
function functionName(param1, param2) {
return param1 + param2;
}
// 函数表达式
const functionExpression = function(param) {
return param * 2;
};
// 箭头函数 (ES6+)
const arrowFunction = (param) => param * 3;
const multiLineArrow = (a, b) => {
const result = a + b;
return result;
};条件语句
javascript
// if-else 语句
if (condition) {
// 执行代码
} else if (anotherCondition) {
// 执行其他代码
} else {
// 默认执行
}
// 三元运算符
const result = condition ? "真值" : "假值";
// switch 语句
switch (value) {
case 'option1':
// 执行代码
break;
case 'option2':
// 执行代码
break;
default:
// 默认执行
}循环语句
javascript
// for 循环
for (let i = 0; i < 10; i++) {
console.log(i);
}
// for...of 循环 (遍历值)
const array = [1, 2, 3];
for (const item of array) {
console.log(item);
}
// for...in 循环 (遍历键)
const object = { a: 1, b: 2 };
for (const key in object) {
console.log(key, object[key]);
}
// while 循环
let i = 0;
while (i < 5) {
console.log(i);
i++;
}DOM操作
元素选择
javascript
// 通过ID选择
const element = document.getElementById('myId');
// 通过类名选择
const elements = document.getElementsByClassName('myClass');
// 通过标签名选择
const divs = document.getElementsByTagName('div');
// CSS选择器 (推荐)
const element = document.querySelector('#myId');
const elements = document.querySelectorAll('.myClass');元素操作
javascript
// 修改内容
element.textContent = '新文本内容';
element.innerHTML = '<strong>HTML内容</strong>';
// 修改样式
element.style.color = 'red';
element.style.fontSize = '16px';
// 修改属性
element.setAttribute('data-value', '123');
element.classList.add('newClass');
element.classList.remove('oldClass');
element.classList.toggle('toggleClass');事件处理
javascript
// 添加事件监听器
element.addEventListener('click', function(event) {
console.log('元素被点击了');
event.preventDefault(); // 阻止默认行为
});
// 移除事件监听器
function clickHandler(event) {
console.log('点击处理器');
}
element.addEventListener('click', clickHandler);
element.removeEventListener('click', clickHandler);
// 常用事件类型
element.addEventListener('mouseover', handleMouseOver);
element.addEventListener('keydown', handleKeyDown);
element.addEventListener('submit', handleSubmit);异步编程
Promise
javascript
// 创建Promise
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('操作成功');
}, 1000);
});
// 使用Promise
myPromise
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});async/await
javascript
// async函数
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('获取数据失败:', error);
}
}
// 使用async函数
fetchData().then(data => {
console.log(data);
});在VitePress中使用JavaScript
1. 客户端脚本
vue
<script setup>
import { ref, onMounted } from 'vue'
const count = ref(0)
onMounted(() => {
console.log('组件已挂载')
})
function increment() {
count.value++
}
</script>
<template>
<div>
<p>计数: {{ count }}</p>
<button @click="increment">增加</button>
</div>
</template>2. 主题增强
javascript
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp({ app, router, siteData }) {
// 全局组件注册
app.component('CustomComponent', CustomComponent)
// 路由守卫
router.beforeEach((to, from, next) => {
console.log('路由变化:', to.path)
next()
})
}
}3. 自定义组件
vue
<!-- .vitepress/theme/components/InteractiveDemo.vue -->
<template>
<div class="interactive-demo">
<h3>{{ title }}</h3>
<div class="demo-content">
<slot />
</div>
<button @click="toggleDemo" class="demo-button">
{{ isVisible ? '隐藏' : '显示' }}演示
</button>
<div v-show="isVisible" class="demo-result">
<pre><code>{{ result }}</code></pre>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const props = defineProps(['title', 'code'])
const isVisible = ref(false)
const result = computed(() => {
try {
return eval(props.code)
} catch (error) {
return `错误: ${error.message}`
}
})
function toggleDemo() {
isVisible.value = !isVisible.value
}
</script>
<style scoped>
.interactive-demo {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
margin: 16px 0;
}
.demo-button {
background: #007acc;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.demo-result {
background: #f5f5f5;
padding: 12px;
border-radius: 4px;
margin-top: 12px;
}
</style>实用工具函数
常用工具
javascript
// 防抖函数
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 节流函数
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 深拷贝
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj.getTime());
if (obj instanceof Array) return obj.map(item => deepClone(item));
if (typeof obj === "object") {
const clonedObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
}数组操作
javascript
const numbers = [1, 2, 3, 4, 5];
// 映射
const doubled = numbers.map(n => n * 2);
// 过滤
const evens = numbers.filter(n => n % 2 === 0);
// 归约
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 查找
const found = numbers.find(n => n > 3);
const foundIndex = numbers.findIndex(n => n > 3);
// 检查
const hasEven = numbers.some(n => n % 2 === 0);
const allPositive = numbers.every(n => n > 0);错误处理
try-catch
javascript
try {
// 可能出错的代码
const result = riskyOperation();
console.log(result);
} catch (error) {
// 错误处理
console.error('操作失败:', error.message);
} finally {
// 无论成功失败都会执行
console.log('清理工作');
}自定义错误
javascript
class CustomError extends Error {
constructor(message, code) {
super(message);
this.name = 'CustomError';
this.code = code;
}
}
function validateInput(input) {
if (!input) {
throw new CustomError('输入不能为空', 'EMPTY_INPUT');
}
if (input.length < 3) {
throw new CustomError('输入长度不足', 'TOO_SHORT');
}
}模块化
ES6模块
javascript
// utils.js - 导出
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export default class Calculator {
multiply(a, b) {
return a * b;
}
}
// main.js - 导入
import Calculator, { PI, add } from './utils.js';
import * as utils from './utils.js';
const calc = new Calculator();
console.log(calc.multiply(2, 3));
console.log(add(1, 2));
console.log(PI);最佳实践
代码规范
javascript
// 使用有意义的变量名
const userAge = 25; // 好
const a = 25; // 不好
// 使用常量
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// 函数应该只做一件事
function calculateTax(price, taxRate) {
return price * taxRate;
}
// 避免深层嵌套
function processUser(user) {
if (!user) return null;
if (!user.isActive) return null;
if (!user.hasPermission) return null;
return processActiveUser(user);
}性能优化
javascript
// 使用文档片段批量操作DOM
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
// 缓存DOM查询
const container = document.getElementById('container');
for (let i = 0; i < items.length; i++) {
// 使用缓存的container而不是重复查询
container.appendChild(createItem(items[i]));
}调试技巧
Console方法
javascript
// 基础日志
console.log('普通日志');
console.warn('警告信息');
console.error('错误信息');
// 表格显示
console.table([{name: 'John', age: 30}, {name: 'Jane', age: 25}]);
// 分组显示
console.group('用户信息');
console.log('姓名: John');
console.log('年龄: 30');
console.groupEnd();
// 计时
console.time('操作耗时');
// 执行一些操作
console.timeEnd('操作耗时');断点调试
javascript
// 代码断点
function complexFunction(data) {
debugger; // 浏览器会在此处暂停
const processed = data.map(item => {
// 处理逻辑
return item * 2;
});
return processed;
}这个JavaScript语法总结涵盖了在Markdown文档和VitePress项目中使用JavaScript的各种方式和最佳实践。
