Onebound技术规范文档


JS

<p>[TOC]</p> <h2>JS</h2> <h3>变量命名</h3> <ul> <li>命名需要由意义</li> </ul> <pre><code class="language-javascript">// 错误示例 let a = 30; 正确示例: let age = 30; </code></pre> <ul> <li>命名不应过长、不允许使用拼音或单词缩写</li> </ul> <pre><code class="language-javascript">// 错误示例 let guojizhuanyun_money = 10.00; // 不允许使用英文、拼音、下划线混杂 let t_p = 1; // total_price缩写,不允许英文单词缩写时只取首字母 // 正确示例 let totalPrice = 1;</code></pre> <ul> <li>统一使用首字母小写的小驼峰体命名规范</li> </ul> <pre><code class="language-javascript">// 错误示例: let GoodsInfoDesc = {}; // 正确示例 let goodsInfoDesc = {}; </code></pre> <h3>目录命名</h3> <ul> <li>要求简洁明了</li> <li>不准使用拼音或拼音缩写</li> <li>不允许驼峰体、下划线共用,多个单词的以驼峰体命名或以-切割</li> </ul> <p>例如:</p> <pre><code>// GoodsItem组件命名 // 错误示例 @/components/goods_item/goods_item.vue @/components/dangeshangpin/dangeshangpin.vue // 切记不要使用拼音去命名 @/components/goods_Item/goods_Item.vue // 也不要以这种方式去命名 // 正确示例 @/components/GoodsItem/GoodsItem.vue or @/components/goods-item/goods-item.vue</code></pre> <h3>方法、类命名:</h3> <p>方法、函数:</p> <pre><code class="language-javascript">// 错误示例 function get_total_price(){ return ''; } export default{ ... methods:{ get_search_sist(){ // methods body } } ... } // 正确示例 function getTotalPrice(){ return ''; } export default{ ... methods:{ getSearchList(){ // methods body } } ... } </code></pre> <p>类:</p> <ul> <li>公共属性和方法:跟变量和函数的命名一样。</li> <li>私有属性和方法:前缀为_(下划线),后面跟公共属性和方法一样的命名方式。</li> </ul> <pre><code class="language-javascript">// 错误示例 class upload_img { // ... } // 正确示例 /** * 上传图片到后端 * @author Cole 2022-03-02 13:37 */ class UploadImg { //.. } // 公有、私有方法和属性 class Student{ var _name = name; // 私有成员 /** * 获取名字 * @author Cole 2022-03-02 13:37 * @return string */ getName(){ return this._name; } /** * 设置名字 * @author Cole 2022-03-02 13:37 * @params name {string} 名字 * @return null */ setName(name){ this._name = name } } var st = new Student('tom'); st.setName('jerry'); console.log(st.getName()); // =&gt; jerry:输出_name私有变量的值 </code></pre> <h3>注释</h3> <ol> <li>在方法、函数前需注释该方法的作者,时间,接收参数,返回值类型、方法作用等</li> </ol> <p>示例</p> <pre><code class="language-javascript">/** * 请求淘宝商品详情接口 * @author Cole 2022-03-02 13:37 * @params num_iid {String} 淘宝商品ID * @return Object {title: '',num_iid: '', sku: {} ....} * @version 1.0.0 * @example requestTaobaoItemApi('659585269247') */ function requestTaobaoItemApi(num_iid){ ... return {} }</code></pre> <table> <thead> <tr> <th>注释名</th> <th>语法</th> <th>含义</th> <th>示例</th> </tr> </thead> <tbody> <tr> <td>@author</td> <td>@author 作者信息 [附属信息:如邮箱、日期]</td> <td>描述此函数作者的信息</td> <td>@author Cole 2022-03-02 13:37</td> </tr> <tr> <td>@params</td> <td>@param 参数名 {参数类型} 描述信息</td> <td>描述参数的信息</td> <td>@param name {String} 传入名称</td> </tr> <tr> <td>@return</td> <td>@return {返回类型} 描述信息</td> <td>描述返回值的信息</td> <td>@return {Object} obapi返回的商品详情信息 {title: '',num_iid: '', sku: {} ....}</td> </tr> <tr> <td>@version</td> <td>@version XX.XX.XX</td> <td>描述此函数的版本号 (可选)</td> <td>@version 1.0.3</td> </tr> <tr> <td>@example</td> <td>@example 示例代码</td> <td>演示函数使用</td> <td>@example requestTaobaoItemApi('659585269247')</td> </tr> </tbody> </table> <h3>空格与运算符:通常运算符 ( = + - * / ) 前后需要添加空格:</h3> <pre><code class="language-javascript">var x = y + z; var values = ["Volvo", "Saab", "Fiat"];</code></pre> <h2>Vue/uni-app</h2> <h3>数据流向</h3> <ul> <li> <p>单个组件数据流</p> <pre><code>props、data/$store/$route、computed (由前面派生) ↓ template/render ↓ 用户交互事件、初始化的异步回调 ↓ data/$store/$route</code></pre> </li> <li>组件间的数据流 <ul> <li>父向子传递用 props</li> <li>子向父传递用 vue 内置的自定义事件,即 this.$emit</li> <li>父子双向传递用 <a target="_blank" href="https://cn.vuejs.org/v2/guide/components-custom-events.html">v-model</a> 或 <a target="_blank" href="https://cn.vuejs.org/v2/guide/components-custom-events.html">.sync</a></li> <li>跨越传递用 vuex(慎用 EventBus)</li> <li>紧密耦合的祖孙间传递也可以考虑用父组件作为中间运输层</li> <li>紧密耦合的兄弟间传递也可以考虑用父组件作为中转运输层</li> </ul></li> </ul> <h3>component</h3> <ul> <li>在对Vue组件命名时,应遵循以下原则 <ul> <li>有意义的 : 不过于具体,也不过于抽象</li> <li>简短 : 2 到 3 个单词</li> <li>具有可读性 : 以便于沟通交流</li> <li>组件命名示例可参考“目录命名”</li> </ul></li> </ul> <pre><code>&lt;!-- 错误示例 --&gt; &lt;btn-group&gt;&lt;/btn-group&gt; &lt;!-- 虽然简短但是可读性差. 使用 `button-group` 替代 --&gt; &lt;ui-slider&gt;&lt;/ui-slider&gt; &lt;!-- ui 前缀太过于宽泛,在这里意义不明确 --&gt; &lt;slider&gt;&lt;/slider&gt; &lt;!-- 与自定义元素规范不兼容 --&gt; &lt;!-- 正确示例 --&gt; &lt;app-header&gt;&lt;/app-header&gt; &lt;user-list&gt;&lt;/user-list&gt; &lt;range-slider&gt;&lt;/range-slider&gt;</code></pre> <h4>组件表达式简单化</h4> <p>Vue.js的表达式是100%的jsvascript的表达式,这使得其功能很强大,但同时也带来了潜在的复杂性,在对组件开发时,应尽量<strong>保持表达式的简单化</strong></p> <p>如果在组件中需要写太多复杂并难以理解的行内表达式,应使用method或者computed属性来替代其功能</p> <pre><code>&lt;!-- 错误示例 --&gt; &lt;template&gt; &lt;h1&gt; {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }} &lt;/h1&gt; &lt;/template&gt; &lt;!-- 正确示例 --&gt; &lt;template&gt; &lt;h1&gt; {{ `${year}-${month}` }} &lt;/h1&gt; &lt;/template&gt; &lt;script type="text/javascript"&gt; export default { computed: { month() { return this.twoDigits((new Date()).getUTCMonth() + 1); }, year() { return (new Date()).getUTCFullYear(); } }, methods: { twoDigits(num) { return ('0' + num).slice(-2); } }, }; &lt;/script&gt;</code></pre> <h4>Props</h4> <p>Vue.js支持传递复杂的JavaScript对象通过props属性,但在开发时,应尽可能的使用原始类型的数据(字符串、数字、布尔值)和函数,尽量避免复杂对象</p> <p>尽量避免复杂对象的好处: = 使得组件 API 清晰直观</p> <ul> <li>只使用原始类型和函数作为 props 使得组件的 API 更接近于 HTML(5) 原生元素。</li> <li>其它开发者更好的理解每一个 prop 的含义,作用</li> <li>传递过于复杂的对象使得我们不能够清楚的知道哪些属性或方法被自定义组件使用,这使得代码难以重构和维护。</li> </ul> <pre><code>&lt;!-- 错误示例 --&gt; &lt;range-slider :config="complexConfigObject"&gt;&lt;/range-slider&gt; &lt;!-- 正确示例 --&gt; &lt;range-slider :values="[10, 20]" min="0" max="100" step="5" :on-slide="updateInputs" :on-end="updateResults"&gt; &lt;/range-slider&gt;</code></pre> <p>在 Vue.js 中,组件的 props 即 API,一个稳定并可预测的 API 会使得你的组件更容易被其他开发者使用。组件 props 通过自定义标签的属性来传递。属性的值可以是 Vue.js 字符串( <code>:attr="value"</code> 或<code>v-bind:attr="value"</code> )或是不传。需要保证组件的 props 能应对不同的情况。</p> <p>验证组件 props 可以保证你的组件永远是可用的(防御性编程)。即使其他开发人员并未按照预想的方法使用时也不会出错。</p> <p>在设置props时,应遵循以下规范</p> <ul> <li>提供默认值</li> <li>使用<code>type</code>属性 校验类型</li> <li>使用props之前应先检查prop是否存在</li> </ul> <pre><code>&lt;template&gt; &lt;input type="range" v-model="value" :max="max" :min="min"&gt; &lt;/template&gt; &lt;script type="text/javascript"&gt; export default { props: { max: { type: Number, // 这里添加了数字类型的校验 default() { return 10; }, }, min: { type: Number, default() { return 0; }, }, value: { type: Number, default() { return 4; }, }, }, }; &lt;/script&gt;</code></pre> <p>在开发组件时,要按照一定的结构组织,使得组件便于理解</p> <p>结构化的好处:</p> <ul> <li>导出一个清晰、组织有序的组件,使得代码易于阅读和理解。同时也便于标准化。</li> <li>按首字母排序properties, data, computed, watches 和 methods使得这些对象内的属性便于查找。</li> <li>合理组织,使得组件易于阅读。(name; extends; props, data and computed; components; watch and methods; lifecycle methods, 等.);</li> <li>使用 name 属性。借助于 vue devtools 可以让你更方便的测试</li> <li>合理的 CSS 结构,如 BEM 或 scss</li> <li>使用单文件 .vue 文件格式来组件代码</li> </ul> <pre><code> &lt;template lang="html"&gt; &lt;div class="Ranger__Wrapper"&gt; &lt;!-- ... --&gt; &lt;/div&gt; &lt;/template&gt; &lt;script type="text/javascript"&gt; export default { // 不要忘记了 name 属性 name: 'RangeSlider', // 组合其它组件 extends: {}, // 组件属性、变量 props: { bar: {}, // 按字母顺序 foo: {}, fooBar: {}, }, // 变量 data() {}, computed: {}, // 使用其它组件 components: {}, // 方法 watch: {}, methods: {}, // 生命周期函数 beforeCreate() {}, mounted() {}, }; &lt;/script&gt; &lt;style scoped&gt; .Ranger__Wrapper { /* ... */ } &lt;/style&gt;</code></pre> <h3>模块复用</h3> <ul> <li>避免重复造轮子,多使用成熟的现成工具/类库/组件,如:lodash、qs、url-parse、date-fns/format 等</li> <li> <p>模块设计原则:</p> <ul> <li>高内聚低耦合、可扩展</li> <li>不要去改变模块输入的数据 (引用类型),如:函数参数、组件 prop</li> <li>模块的入参为可选 Boolean 时,默认值应设计为 false</li> </ul> </li> <li>方法接口的设计</li> </ul> <pre><code>// 参数类型与个数要保持稳定 // 建议参数不要超过3个,且预留一个 options 对象,以提高扩展性 // 方法尽量纯净 (纯函数思想) export function myMethod1(a, options) {} // 当必选参数只有一个时 export function myMethod2(a, b, options) {} // 当必选参数只有两个时 export function myMethod3(options) {} // 当必选参数有两个以上时 export function myMethod4(options) {} // 当所有参数都是可选时 // 有时为了提高灵活性,参数类型可以是两重,一重是期望值,另一重是返回期望值的函数 (可带参) export function myMethod5(a) { a = typeof a === 'function' ? a() : a }</code></pre> <ul> <li>使用 extends 混入 (相关命名需要加 ex 前缀,防止覆盖)</li> </ul>

页面列表

ITEM_HTML