在这段时间里我不停的做着 vue 的技术分享,虽然不是什么深层次的代码底能架构,如果底层架构真说出来,我就不会做 vue.js 2.0 从基础到组件了,就会分享 Vue 从底层到还是到底层。我相信能来看我这次分享的朋友都是在工作开发层面上面临着一些问题。此次分享我们先抛开 Vue - router 和 Vuex, 很多朋友都觉得 Vuex 和 router 比较难,大错特错!
我对 Vue 2.0 认知,能 it 前端框架的认知,在我们不算底层原理的情况下,什么才是精髓,那就是基础的方法和一些 api 介绍,随着现代数据量庞大,业务逻辑也变得更加复杂,随着数据情景的不同展示,jquery,angular1.0 等一系列框架,已经满足不了开发的需求了,如何用数据驱动去管理数据,在我认知里,前后端联调,对接口,通过什么?那过 json 数据来传递着一切的信息。
我们操作 dom 来分析数据,那就是用屠龙刀去切菜,用数据驱动去改变数据,那才叫细功出好活。还有我们如何更好的通过组件来让一个复杂的页面划分为代码精简,易维护,可复用,阔展性强的组件集合!
来进行头图的划分。)
- prop:{[img]}
这样一算你们会发现一个小小的登陆就划分出 6 个组件,可能给你的感觉分的太细,那我也感觉分的太细,那我为什么要分的那么细呢,那就是增强可复用性,可阔展性。
那我何去解这个组件太过于细分的问题,我们可以合并那些东西,以我一眼看过去,唯一能合并的就是中间一套注册体系,我们把 2,3,4,5,7, 这几个细组件合并到 login.Vue 组件里,在这个层面上,我们只要暴露出四个输入框内容向外传递的数据,这样一个页面整体就我们拆开来了,对于每个页面的代码量就减少了,对于维护,改 bug 是一个很大的帮助。
Vue 的在项目中如何去做好一个体系问题,最主要的就是 template 里整体的组织,如何用好的组织体系方便的展现复杂的逻辑操作,我个人认为而不是通过 new Vue 去操控整体,反正 new Vue 里的一切选项是着 template 这个组织体系走的,如果是一个房子,template 就是地基,new Vue 里的选项就是水泥石头。
上面一眼就能让人明白,不用往下看就明白我所要改变数据是为了什么,就这一行模板语法用 javascript 表达式写让你能明白一切。
- <p @click='show = false'></p>
。
- @touchmove.prevent.stop
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher 。这是为什么 Vue 提供一个更通用的方法通过 watch 选项,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。
基于这个官方的理解再总结我个人的整体理解。给出 computed 和 watch 的总结,记住这几点的总结,在做项目的时候想想这些总结,选择你的应用方法
其实我觉得计算属性也好,computed,watch 这几个都不是有多难,如果浅层面上看很容易理解,如果从深层面上看,很多小伙伴会存在什么问题,就是会滥用,混用,这些计算属性,虽然最后结果都能实现,就像条条大路通罗马,你走的是最远的路,想返回可能都难
我就举以上几个简单的例子,但是我想说的就是两点基础非常重要。
要如何结合三大牛 B 特性:
如果你看到这个需求,你花 3 分种时间如何去用以上三大特性做出两种解决方法你就是 Vue 精通者。
我还是感觉第二个方便点。
如何去写组件,从什么地方开始写起,如果你对基础 api 已经了如指掌了,那你就可以开手动组件了,组件要学会利用几个组件的很大的特性,最大的特性我就不用说了,用 props 接数据,用 $emit 去触发事件 用 v-on 去接收自定义事件,有时候你会发现有时候通过父组件传递来的数据,我们在组件内部一直需要改动,那我们不得不用 watch 方法去复制一个复本,再进行操作,那我们有什么好办法,如更面临更多组件套组件的模式下,如果利用特性 api 去做最简便的写法,那就是
、
- $parent
、
- $children
、
- $root
、
- $el
这五大特性。
- $refs
始终基于模块的方式来构建你的 app,每一个子模块只做一件事情。
Vue.js 的设计初衷就是帮助开发者更好的开发界面模块。一个模块是应用程序中独立的一个部分。
每一个 Vue 组件 (等同于模块) 首先必须专注于解决一个单一的问题,独立的, 可复用的, 微小的 and 可测试的。
如果你的组件做了太多的事或是变得臃肿,请将其拆分成更小的组件并保持单一的原则。一般来说,尽量保证每一个文件的代码行数不要超过 100 行。也请保证组件可独立的运行。比较好的做法是增加一个单独的 demo 示例。
组件的命名需遵从以下原则:
同时还需要注意:
为什么?因为组件是通过组件名来调用的。所以组件名必须简短、富有含义并且具有可读性。
- <!-- 推荐 -->
- <app-header>
- </app-header>
- <user-list>
- </user-list>
- <range-slider>
- </range-slider>
- <!-- 避免 -->
- <btn-group>
- </btn-group>
- <!-- 虽然简短但是可读性差. 使用 `button-group` 替代 -->
- <ui-slider>
- </ui-slider>
- <!-- ui 前缀太过于宽泛,在这里意义不明确 -->
- <slider>
- </slider>
- <!-- 与自定义元素规范不兼容 -->
Vue.js 的表达式是 100% 的 Javascript 表达式。这使得其功能性很强大,但也带来潜在的复杂性。因此,你应该尽量保持表达式的简单化。
如果你发现写了太多复杂并难以阅读的行内表达式,那么可以使用 method 或是 computed 属性来替代其功能。
- <!-- 推荐 -->
- <template>
- <h1>
- {{ `${year}-${month}` }}
- </h1>
- </template>
- <script type="text/javascript">
- export
- default {
- computed:
- {
- month() {
- return this.twoDigits((new Date()).getUTCMonth() + 1);
- },
- year() {
- return (new Date()).getUTCFullYear();
- }
- },
- methods: {
- twoDigits(num) {
- return ('0' + num).slice( - 2);
- }
- },
- };
- </script>
- <!-- 避免 -->
- <template>
- <h1>
- {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}`
- }}
- </h1>
- </template>
虽然 Vue.js 支持传递复杂的 JavaScript 对象通过 props 属性,但是你应该尽可能的使用原始类型的数据。尽量只使用 JavaScript 原始类型 (字符串、数字、布尔值) 和 函数。尽量避免复杂的对象。
组件的每一个属性单独使用一个 props,并且使用函数或是原始类型的值。
- <!-- 推荐 -->
- <range-slider
- :values="[10, 20]"
- min="0"
- max="100"
- step="5"
- :on-slide="updateInputs"
- :on-end="updateResults">
- </range-slider>
- <!-- 避免 -->
- <range-slider :config="complexConfigObject"></range-slider>
在 Vue.js 中,组件的 props 即 API,一个稳定并可预测的 API 会使得你的组件更容易被其他开发者使用。
组件 props 通过自定义标签的属性来传递。属性的值可以是 Vue.js 字符串
或是不传。你需要保证组件的 props 能应对不同的情况。
- (:attr="value" 或 v-bind:attr="value")
验证组件 props 可以保证你的组件永远是可用的 (防御性编程)。即使其他开发者并未按照你预想的方法使用时也不会出错。
- <template>
- <input type="range" v-model="value" :max="max" :min="min">
- </template>
- <script type="text/javascript">
- export
- default {
- props:
- {
- max:
- {
- type:
- Number,
- // 这里添加了数字类型的校验
- default() {
- return 10;
- },
- },
- min: {
- type: Number,
- default() {
- return 0;
- },
- },
- value: {
- type: Number,
- default() {
- return 4;
- },
- },
- },
- };
- </script>
在 Vue.js 组件上下文中,this 指向了组件实例。因此当你切换到了不同的上下文时,要确保 this 指向一个可用的 component 变量。
换句话说,不要在编写这样的代码 const self = this; ,而是应该直接使用变量 component。
将组件 this 赋值给变量 component 可用让开发者清楚的知道任何一个被使用的地方,它代表的是组件实例。
- <script type="text/javascript">
- export
- default {
- methods:
- {
- hello() {
- return 'hello';
- },
- printHello() {
- console.log(this.hello());
- },
- },
- };
- </script>
- <!-- 避免 -->
- <script type="text/javascript">
- export
- default {
- methods:
- {
- hello() {
- return 'hello';
- },
- printHello() {
- const self = this; // 没有必要
- console.log(self.hello());
- },
- },
- };
- </script>
按照一定的结构组织,使得组件便于理解。
详情
- oocss -
。
- ?;
- <template lang="html">
- <div class="Ranger__Wrapper">
- <!-- ... -->
- </div>
- </template>
- <script type="text/javascript">
- export
- default {
- // 不要忘记了 name 属性
- name:
- 'RangeSlider',
- // 组合其它组件
- extends: {},
- // 组件属性、变量
- props: {
- bar: {},
- // 按字母顺序
- foo: {},
- fooBar: {},
- },
- // 变量
- data() {},
- computed: {},
- // 使用其它组件
- components: {},
- // 方法
- watch: {},
- methods: {},
- // 生命周期函数
- beforeCreate() {},
- mounted() {},
- };
- </script>
- <style scoped>
- .Ranger__Wrapper { /* ... */ }
- </style>
Vue.js 提供的处理函数和表达式都是绑定在 ViewModel 上的,组件的每一个事件都应该按照一个好的命名规范来,这样可以避免不少的开发问题,具体可见如下 为什么 。
,
- upload-success
以及
- upload-error
,
- dropzone-upload-success
(如果需要前缀的话)。
- dropzone-upload-error
)或是形容词(如
- client-api-load
)结尾。(出处)
- drive-upload-success
Vue.js 支持组件嵌套,并且子组件可访问父组件的上下文。访问组件之外的上下文违反了基于模块开发的第一原则。因此你应该尽量避免使用
。
- this.$parent
Vue.js 支持通过 ref 属性来访问其它组件和 HTML 元素。并通过
可以得到组件或 HTML 元素的上下文。在大多数情况下,通过
- this.$refs
来访问其它组件的上下文是可以避免的。在使用的的时候你需要注意避免调用了不恰当的组件 API,所以应该尽量避免使用
- this.$refs
。
- this.$refs
来实现。
- this.$refs
而不是
- this..$ref
,
- JQuery
,
- document.getElement*
。
- document.queryElement
- <!-- 推荐,并未使用 this.$refs -->
- <range :max="max" :min="min" @current-value="currentValue" :step="1">
- </range>
- <!-- 使用 this.$refs 的适用情况-->
- <modal ref="basicModal">
- <h4>
- Basic Modal
- </h4>
- <button class="primary" @click="$refs.basicModal.close()">
- Close
- </button>
- </modal>
- <button @click="$refs.basicModal.open()">
- Open modal
- </button>
- <!-- Modal component -->
- <template>
- <div v-show="active">
- <!-- ... -->
- </div>
- </template>
- <script>
- export
- default {
- // ...
- data() {
- return {
- active:
- false,
- };
- },
- methods: {
- open() {
- this.active = true;
- },
- hide() {
- this.active = false;
- },
- },
- // ...
- };
- </script>
- <!-- 如果可通过 emited 来做则避免通过 this.$refs 直接访问 -->
- <template>
- <range :max="max" :min="min" ref="range" :step="1">
- </range>
- </template>
- <script>
- export
- default {
- // ...
- methods:
- {
- getRangeCurrentValue() {
- return this.$refs.range.currentValue;
- },
- },
- // ...
- };
- </script>
Vue.js 的组件是自定义元素,这非常适合用来作为样式的根作用域空间。可以将组件名作为 css 类的命名空间。
使用组件名作为样式命名的前缀,可基于 BEM 或 OOCSS 范式。同时给 style 标签加上 scoped 属性。加上 scoped 属性编译后会给组件的 class 自动加上唯一的前缀从而避免样式的冲突。
- <style scoped>
- /* 推荐 */
- .MyExample { }
- .MyExample li { }
- .MyExample__item { }
- /* 避免 */
- .My-Example { } /* not scoped to component or module name, not BEM compliant */
- </style>
使用 Vue.js 组件的过程中会创建 Vue 组件实例,这个实例是通过自定义属性配置的。为了便于其他开发者使用该组件,对于这些自定义属性即组件 API 应该在 README.md 文件中进行说明。
在模块目录中添加 README.md 文件:
- range-slider/
- ├── range-slider.Vue
- ├── range-slider.less
- └── README.md
在 README 文件中说明模块的功能以及使用场景。对于 Vue 组件来说,比较有用的描述是组件的自定义属性即 API 的描述介绍。
我觉得吧!无论学什么,学好基础才是最重要,我的学习方式是从浅入深,而不是深入浅出,只有基础打的好,才会有更好的解决方案,Vue 一切的组件功能都围绕着基础。
实录: 《周志祥:Vue.js 2.0 基础组件实战解析》
来源: http://www.tuicool.com/articles/mEbQzqN