前端开发规范

2025-05-27  本文已影响0人  一个记事本

前端开发规范

一、代码风格

1. 缩进

<script setup>
function fetchData() {
  return axios.get('/api/data')
    .then(response => {
      return response.data;
    })
    .catch(error => {
      console.error('Error fetching data:', error);
    });
}
</script>

2.大括号使用

if (condition) {
  executeSomeLogic();
} else {
  executeAlternativeLogic();
}

3.括号使用

function logMessage() {
  console.log('Message logged');
}

logMessage();

4.逗号使用

const person = {
  name: 'John Doe',
  age: 30,
  occupation: 'Developer' // 没有多余的逗号
};

const numbers = [1, 2, 3]; // 没有多余的逗号

5.引号使用

const greeting = 'Hello, World!';
const quote = "Don't worry, be happy!";

二、命名规范

1.变量命名

// 正确示例
let userName = 'John Doe';
let userAge = 30;
let isLoggedIn = true;

// 错误示例
let uName = 'John Doe'; // 变量名不够清晰
let data = 30; // 变量名过于模糊
let flag = true; // 变量名不够具体

2.常量命名

const API_URL = '<https://api.example.com>';
const MAX_LIMIT = 100;
const DAYS_IN_WEEK = 7;

3.函数命名

// 正确示例
function fetchUserData(userId) {
  // 获取用户数据的逻辑
}

function validateFormInputs(form) {
  // 验证表单输入的逻辑
}

// 错误示例
function ud(userId) { // 函数名不够清晰
  // 获取用户数据的逻辑
}

function vf(form) { // 函数名不够清晰
  // 验证表单输入的逻辑
}

4.类命名

class UserManager {
  // 用户管理类的逻辑
}

class DataProcessor {
  // 数据处理类的逻辑
}

三、注释规范

1.单行注释

// 用户名验证
if(userName === 'admin') {

}
// 用户名验证正则表达式,规则为:长度4-20位,只能包含字母、数字和下划线
const usernameRegex = /^[a-zA-Z0-9_]{4,20}$/;

2.多行注释

/*
 * 用户管理类
 * 负责用户数据的增删改查操作。
 */
class UserManager {
  async getUsers() {
    // 获取用户列表
  }

  async addUser(user) {
    // 添加用户
  }

  async deleteUser(userId) {
    // 删除用户
  }
}
/*
 * 定义用户资料卡片的样式。
 * 包括背景颜色、边框、圆角和内边距。
 */
.user-profile {
  background-color: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
}

3.函数注释

/**
* 格式化日期为指定的字符串格式
* @param {Date} date - 要格式化的日期对象
* @param {string} format - 目标日期格式,如'yyyy-MM-dd', 'MM/dd/yyyy'等
* @returns {string} 格式化后的日期字符串
* @throws {Error} 如果format参数格式不正确或不支持
 */
function formatDate(date, format) {
  // 格式化日期的逻辑
}

四、组件开发规范

1.组件命名

<!-- 正确示例:UserCard.vue -->
<template>
  <div class="user-card">
    <img :src="user.avatar" :alt="user.name" class="user-avatar" />
    <h3 class="user-name">{{ user.name }}</h3>
    <p class="user-info">{{ user.info }}</p>
  </div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  user: {
    type: Object,
    required: true
  }
});
</script>

<style scoped>
.user-card {
  /* 样式定义 */
}
</style>

2.组件结构

<template>
  <!-- 组件模板部分 -->
  <div class="login-form">
    <h2>{{ onLogin }}</h2>
  </div>
</template>

<script setup>
    // props
    const props = defineProps({
        onLogin: {
            type: string,
            default: '登录',
            required: true
        }
    });
</script>

<style scoped>
/* 组件样式部分 */
.login-form {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
}

</style>

3.组件交互

3.1 父子组件通信

<!-- 父组件:ParentComponent.vue -->
<template>
  <div>
    <child-component :user="selectedUser" @update-user-info="handleUserInfoUpdate" />
  </div>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
import { ref } from 'vue';

const selectedUser = ref({
  id: 1,
  name: 'John Doe',
  email: 'john@example.com'
});

const handleUserInfoUpdate = (updatedUser) => {
  // 处理用户信息更新的逻辑
  console.log('User info updated:', updatedUser);
  selectedUser.value = updatedUser;
};
</script>
<!-- 子组件:ChildComponent.vue -->
<template>
  <div>
    <h3>User Information</h3>
    <p>Name: {{ user.name }}</p>
    <p>Email: {{ user.email }}</p>
    <button @click="updateUserInfo">Update Info</button>
  </div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  user: {
    type: Object,
    required: true
  }
});

const emit = defineEmits(['update-user-info']);

const updateUserInfo = () => {
  const updatedUser = {
    ...props.user,
    name: 'Updated Name',
    email: 'updated@example.com'
  };
  emit('update-user-info', updatedUser); // 触发自定义事件,将更新后的用户信息传递给父组件
};
</script>

3.2 兄弟组件通信

4.组件性能优化

<template>
  <div>
    <button @click="activeTab = 'TabA'">Tab A</button>
    <button @click="activeTab = 'TabB'">Tab B</button>
    <button @click="activeTab = 'TabC'">Tab C</button>

    <keep-alive>
      <component :is="activeTabComponent" />
    </keep-alive>
  </div>
</template>

<script setup>
import TabA from './TabA.vue';
import TabB from './TabB.vue';
import TabC from './TabC.vue';
import { ref, computed } from 'vue';

const activeTab = ref('TabA');

const activeTabComponent = computed(() => {
  return activeTab.value;
});
</script>

五、CSS 规范

1.命名规范

/* 错误示例 */
.red-button {
  background-color: red;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 正确示例 */
.primary-button {
  background-color: #4CAF50;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 基于组件名的命名空间示例 */
.user-card {
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  padding: 16px;
  margin-bottom: 16px;
}

.user-card-avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;
}

2.样式组织

// 变量定义
@primary-color: #4CAF50;
@secondary-color: #2196F3;
@border-radius: 4px;
@box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

// 混合定义
.mixin-box-shadow(@shadow: @box-shadow) {
  box-shadow: @shadow;
}

// 样式定义
.primary-button {
  background-color: @primary-color;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: @border-radius;
  cursor: pointer;
  .mixin-box-shadow();
}

.secondary-button {
  background-color: @secondary-color;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: @border-radius;
  cursor: pointer;
  .mixin-box-shadow();
}

3.样式顺序

.card {
  position: relative;
  width: 300px;
  height: 200px;
  margin: 20px auto;
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background-color: white;
  color: #333;
  font-size: 16px;
  line-height: 1.5;
  text-align: left;
  transition: transform 0.3s ease;
  cursor: pointer;
}

.card:hover {
  transform: translateY(-5px);
}

4.媒体查询

/* 桌面端样式 */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 16px;
}

/* 平板端样式 */
@media (max-width: 1024px) {
  .container {
    max-width: 800px;
  }
}

/* 移动端样式 */
@media (max-width: 768px) {
  .container {
    max-width: 100%;
    padding: 0 12px;
  }
}

六、文件名规范

1.组件文件

// 正确示例
UserCard.vue
LoginForm.vue
HomePage.vue

// 错误示例
user-card.vue
login_form.vue
home-page.vue

2.JS 文件

// 正确示例
userData.js
formValidation.js
apiService.js

// 错误示例
user-data.js
form-validation.js
api-service.js

3.CSS 文件

/* 正确示例(驼峰命名法) */
globalStyles.less
componentStyles.css
themeVariables.less

/* 正确示例(短横线命名法) */
global-styles.less
component-styles.css
theme-variables.less

/* 错误示例 */
global_styles.less
component_styles.css
theme_variables.less

4.图片文件

<!-- 正确示例(短横线命名法) -->
<img src="images/user-avatar.png" alt="User Avatar" />
<img src="images/logo.svg" alt="Logo" />

<!-- 正确示例(下划线命名法) -->
<img src="images/user_avatar.png" alt="User Avatar" />
<img src="images/logo.svg" alt="Logo" />

<!-- 错误示例 -->
<img src="images/useravatar.png" alt="User Avatar" />
<img src="images/logo-svg.svg" alt="Logo" />

七、JS 编程规范

1.变量声明

// 使用const声明常量
const API_URL = 'https://api.example.com';
const MAX_LIMIT = 100;

// 使用let声明变量
let count = 0;
let userLoggedIn = false;

// 错误示例(使用var)
var userName = 'John Doe';
var itemCount = 5;

// 变量使用前必须声明
let userInput;
userInput = prompt('Enter your name');
console.log('Hello, ' + userInput);

// 错误示例(变量使用前未声明)
console.log(userInput);
userInput = prompt('Enter your name');

2.对象和数组

// 创建对象
const user = {
  id: 1,
  name: 'John Doe',
  age: 30,
  email: 'john@example.com'
};

// 解构对象
const { id, name, age, email } = user;
console.log(`User ID: ${id}, Name: ${name}, Age: ${age}, Email: ${email}`);
// 使用map方法处理数组
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(number => number * 2);
console.log(doubledNumbers); // 输出:[2, 4, 6, 8, 10]

// 使用filter方法过滤数组
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // 输出:[2, 4]

// 使用reduce方法计算数组的和
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 输出:15

3.函数

// 函数表达式
const greet = function(name) {
  console.log(`Hello, ${name}!`);
};
greet('John');

// 箭头函数
const square = x => x * x;
console.log(square(5)); // 输出:25

const add = (a, b) => a + b;
console.log(add(3, 7)); // 输出:10
// 函数参数过多的示例(不推荐)
function createPerson(firstName, lastName, age, gender, occupation) {
  // 创建人物对象的逻辑
}

// 使用对象作为参数的示例(推荐)
function createPerson({ firstName, lastName, age, gender, occupation }) {
  // 创建人物对象的逻辑
}

// 调用函数
createPerson({
  firstName: 'John',
  lastName: 'Doe',
  age: 30,
  gender: 'male',
  occupation: 'developer'
});

// 函数参数默认值示例
function multiply(a, b = 1) {
  return a * b;
}

console.log(multiply(5)); // 输出:5
console.log(multiply(5, 3)); // 输出:15

4.异步编程

// 使用async/await获取用户数据
async function fetchUserData(userId) {
  try {
    const response = await axios.get(`/api/users/${userId}`);
    return response.data;
  } catch (error) {
    console.error('Error fetching user data:', error);
    throw error;
  }
}

// 调用异步函数
async function displayUserData(userId) {
  try {
    const userData = await fetchUserData(userId);
    console.log('User Data:', userData);
  } catch (error) {
    console.error('Failed to display user data:', error);
  }
}

displayUserData(1);
// 使用Promise获取用户数据
function fetchUserDataPromise(userId) {
  return new Promise((resolve, reject) => {
    axios.get(`/api/users/${userId}`)
      .then(response => {
        resolve(response.data);
      })
      .catch(error => {
        reject(error);
      });
  });
}

// 调用Promise
fetchUserDataPromise(1)
  .then(userData => {
    console.log('User Data:', userData);
  })
  .catch(error => {
    console.error('Error fetching user data:', error);
  });

5.防御性编程

// 对象判空
function getUserRole(user) {
  if (!user) {
    console.warn('User object is null or undefined');
    return null;
  }
  return user.role || 'guest';
}

// 对象判空,链式调用
function getUserRole(user) {
  return user?.role || 'guest';
}

// 数组判空
function getFirstItem(items) {
  if (!items || !items.length) {
    console.warn('Items array is empty or not an array');
    return null;
  }
  return items[0];
}

// 字符串判空
function displayMessage(message) {
  if (!message || message.trim() === '') {
    console.warn('Message is empty or contains only whitespace');
    return 'No message to display';
  }
  return message;
}

// 函数调用示例
const user = {
  name: 'John Doe',
  role: 'admin'
};
console.log(getUserRole(user)); // 输出:'admin'

const items = ['apple', 'banana', 'orange'];
console.log(getFirstItem(items)); // 输出:'apple'

console.log(displayMessage('Hello, World!')); // 输出:'Hello, World!'
console.log(displayMessage('')); // 输出:'No message to display'
// 函数参数类型检查
function calculateTotal(prices) {
  if (!Array.isArray(prices)) {
    throw new TypeError('Expected prices to be an array');
  }

  if (!prices.every(price => typeof price === 'number')) {
    throw new TypeError('All elements in prices array must be numbers');
  }

  return prices.reduce((total, price) => total + price, 0);
}

// 调用函数示例
try {
  const prices = [10, 20, 30];
  const total = calculateTotal(prices);
  console.log('Total:', total); // 输出:60
} catch (error) {
  console.error('Error calculating total:', error.message);
}

// 错误调用示例
try {
  const invalidPrices = [10, '20', 30];
  calculateTotal(invalidPrices);
} catch (error) {
  console.error('Error calculating total:', error.message); // 输出:All elements in prices array must be numbers
}
// 使用try/catch处理异常
try {
  const result = divide(10, 0);
  console.log('Result:', result);
} catch (error) {
  console.error('Error:', error.message);
}

/**
 * 除法函数
 * @param {number} a - 被除数
 * @param {number} b - 除数
 * @returns {number} - 结果
 */
function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}
上一篇 下一篇

猜你喜欢

热点阅读