# vue 单文件组件 ## 基本原则 ### 总体原则 1. 使用`setup`语法,`组合式 API`,而非`选项式 API` 2. 不要使用`mixins`,vue3中已不推荐使用,参考:[mixins](https://cn.vuejs.org/api/options-composition.html#mixins),[app.mixin()](https://cn.vuejs.org/api/application.html#app-mixin) 3. 不要在 `updated` 钩子中更改组件的状态,这可能会导致无限的更新循环! 4. 慎用`provide`和`inject`。 5. 慎用`watch`,能在`数据变化`源头进行操作的,就不要用`watch`。 6. 适时进行`组件拆分`,组件中代码长度不宜超过`300`行(概数,`少于`或者`略超`都可接受),宽度不宜超过`3/4 屏幕宽度`,代码应适时`空格`、`换行`、`空行`。 7. 每次提交代码之前,应移除`console.log`等无用代码。 ### 组件拆分原则 1. 通常`v-for`遍历的`每一项`,应拆分为`独立组件`。除非`场景极其简单`,或者`确定后续不再更改`。 2. 通常`v-if`对应的`每一项`,应拆分为`独立组件`。除非`场景极其简单`,或者`确定后续不再更改`。 3. 通常`modal`组件中的内容,应拆分为`独立组件`。 4. 通常`drawer`组件中的内容,应拆分为`独立组件`。 5. 通常`popover`组件中的内容,应拆分为`独立组件`。 6. 通常`表单`应拆分为`独立组件`。 7. `过于复杂`的组件应设法拆分为`多个独立组件` ### 模板-template 1. `v-if`和`v-for`不要用在同一个节点上。 2. `v-for`必须加独立的唯一的`key`,如果API不返回,客户端应设法构造一个`唯一的可逆的key` 3. 任意节点的`key`都不能用`随机数` 4. 不要在模板里写`函数`,例如:``,这是糟糕的做法。 5. 不要在模板里写过多`js表达式`,请使用`计算属性`或者其他定义好的值。例如:绑定的样式对象直接在模板里书写,这是糟糕的做法。 6. 模板中的字符串使用`双引号`包裹,例如:`
` 7. 不要使用`v-else`,当在模板中存在条件判断时,应写完整的`v-if`,例如:`
`。使用`v-else`不利于后续扩展 8. 请使用缩写指令,`@`代替`v-on`,`:`代替`v-bind`,`#`代替`v-slot` 9. 当节点上有`多个属性`时,应对每一个属性进行`换行`。 10. 在模板中使用`自定义组件`时,应写成`大写驼峰`(参考下方组件命名),而非`小写中横线`。 ### 脚本-script 1. `js`中的字符串使用`单引号`包裹,例如:`const user_name = ref('zhangsan')` 2. 代码不宜写成一坨,要进行合理的`空行`。通常做`相似事情的代码`可连续书写,当代码进行到下一类事情时,需`空行`。例如声明多个变量,可连续书写,当将要声明一个函数时,需`空行`后再进行函数声明。 3. `关键词`与`操作符`之间要进行合理的`空格` 4. `注释`要清晰,必要时添加`文档`进行说明。请参考[jsdoc](https://jsdoc.nodejs.cn/)进行注释。 ### 样式-style 1. 在样式中不要直接使用`元素选择器`。 2. 在样式中不要使用 `deep` ## 命名规范 为了`统一风格`,特对于项目中的`命名`进行一些规定。下方给出了一个项目的`src`目录中关键文件的`命名示例`。 ``` src/ |- index.js |- App.vue |- assets/ |- images/ |- site-logo.png |- man.svg |- woman.svg |- audio/ |- response-media.mp3 |- video/ |- movie.mp4 |- store/ |- index.js |- use-counter.js |- routes/ |- index.js |- components/ |- account/ |- Login.vue |- Register.vue |- product/ |- ProductCreateForm.vue |- ProductDetail.vue |- shop-online/ |- ShopOnlineConfirmForm.vue |- ShopOnlineStatus.vue |- views/ |- Index.vue |- About.vue |- Login.vue |- ProductDetail.vue ``` ### 文件夹名称 `文件夹名称`一律`小写`,用`中横线`分隔。例如:`shop-online` ### 文件名称 除了`组件名`之外,其他类型的文件一律使用`小写英文字母`,使用`中横线`分隔。例如:`response-media.mp3`、`site-logo.png` ### 第三方组件名在模板中的使用 对于`第三方组件`,使用`小写`、`中横线`的方式进行书写。 ```vue ``` ### 自定义组件名称 `组件名`使用`驼峰`形式命名,例如:`Index.vue`、`ProductDetail.vue`。 ### 项目内自定义组件 对于`项目内`的`自定义组件`,使用`大写`、`驼峰`方式进行书写。 ```vue ``` ### props命名 `props`命名使用`小写`、`下划线`形式命名。例如下方的`props.user_age`、`props.user_name`。 ```vue ``` ### emit命名 `emit`命名使用`小写`、`驼峰`形式,例如:`priceChange`,`messageFinished`。 > 无需加`on`前缀,例如:`onPriceChange`,这是错误做法。 ```vue ``` ### 变量命名 同`props`命名,使用`小写`、`下划线`形式。 ```js const my_name = ref('张三'); const user_age = 18; const theme_color = 'dark'; ``` ### 常量命名 `常量`使用`大写`字母加`下划线`的形式命名。 ```js const PROJECT_TITLE = '小数智能'; // 项目名称 const EXPIRE_VALUE = 3600; // 过期时间 ``` ### 函数命名 `函数`名称同`emit`命名 ```js function handleClick(){ } /** * 获取产品的ID * @params {string} id - 产品ID **/ function getProductInfo(id){ } ``` ### 类命名 `类`使用`大写`、`驼峰`形式命名。 ```js class Human{ } class Animals{ } class ProductOrder{ } ``` ## 关键顺序约定 ### 单文件组件顺序 `单文件组件`中区块顺序按照`template`,`script`,`style`顺序进行书写。 ```vue ``` ### 模板中元素属性的顺序 在模板中为元素绑定属性,需要遵循一定的顺序,大致顺序如下: 1. `v-`开头的指令,`v-if`、`v-show`、`v-for` 2. `key`、`class`、`style`、`id`、`title`等 3. 自定义属性,例如: `:age="18"`、`:price="300"` 4. 事件 `@click`、`@input`、`@change` 等 ```vue ``` ### `script`标签内的顺序 在`单文件组件`中,各项顺序大致如下: 1. `import` 2. `defineProps` 3. `defineEmits` 4. `ref`、`reactive`、`let`、`const`、`var`等 5. `computed` 6. `watch` 7. `事件处理`方法 8. `生命周期钩子`:`onCreated`、`onMounted`、`onUpdated`、`onBeforeUnmount` 9. `defineExpose` ### css属性规则的顺序 样式的定义应遵循一定的顺序。 建议遵循以下顺序: 1. 布局定位属性:display / position / float / clear / visibility / overflow 2. 自身属性:width / height / margin / padding / border / background 3. 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word 4. 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background:linear-gradient … > 参考:https://guide.aotu.io/docs/css/code.html#%E5%B1%9E%E6%80%A7%E4%B9%A6%E5%86%99%E9%A1%BA%E5%BA%8F ```css .title{ display: block; position: relative; float: left; width: 100px; height: 100px; margin: 0 10px; padding: 20px 0; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; color: #333; background: rgba(0,0,0,.5); -webkit-border-radius: 10px; -moz-border-radius: 10px; -o-border-radius: 10px; -ms-border-radius: 10px; border-radius: 10px; } ```