iOS vue学习:组件、路由、指令、状态管理

264 阅读7分钟

最近三个月来公司项目都是用vue+原生的方式来进行开发,虽然体验方面比不了RN开发,离原生的项目也有不小的差距,抛开这些因素,在核心功能保持较少变动的情况下,使用vue的的确确缩短了项目开发的周期。既然是前端小白,那么中间踩坑也是难免的,在此记录一下学习心得和开发过程。

虽然语法多种多样,但每一门语法都是一个工具,当我们通过熟练学习后就成了我们自己手中的工具,不同的工具适应不同的场景才能在工作中,尽可能使效率最大化。

what‘s a vue?

vue的核心库只关心图层,且易于上手,兼具兼容性,整体提升前端层面的开发效率。

提高渲染效率,帮助我们减少不必要的DOM操作,多去关注业务逻辑层面的工作。

项目组成

略过语法部分,看一看项目的骨架:

vue.js + vue-router+vuex

webpack

npm

css预处理器:stylus/scss

Promise + axios

项目文件结构: node_modules: 依赖包管理工具

src: 项目主体部分

package.json: 包含名称、描述和版本之类的信息

通过入口文件main.js进入

new Vue({  
router,  
store,  
render: h => h(App)
}).$mount('#app')

ES6 箭头函数的写法

render: h => h(App)

原生写法

render: function (createElement) {
    return createElement(App);
}

基础语法

vue.js

组件

用于拆分出Vue中的功能,减轻Vue的代码量,主要是针对UI的封装提高重用率

把可复用的组件功能提出来,形成一个标签。而vue组件就是模版的意思和我们常见的template是同样的

1.注册组件

凡是在new vue中注册的就是局部的,vue外面通过变量形式注册的为全局的。

全局组件

方式一

vue.js的组件是自定义html元素,参数一是元素名;参数二是可选项

Vue.component('myComponents', {
    template: <div><h1>h1</h1><h3>h3</h3></div>
})// template属性指向的模版内容,只能存在一个根元素

方式二(推荐)

Vue.component('myComponents', {
    template: '#temp'
})

<template id='temp'>
 <div>
 	<h1>h1</h1>
 	<h3>h3</h3>
 </div>
</template>

局部/私有组件

var Child = {
  template: '<h1>自定义组件!</h1>'
}// 通过对象变量的形式,定义了一个组件模版对象

new Vue({
  el: '#app',
  components: {
    // <runoob> 将只在父模板可用
    'runoob': Child
  }
})

2.引用组件

通过组件名来引用,注意使用驼峰法myComponents

<my-components />

3.组件传值

正向传值(props)

父组件给子组件传值,在引用组件的时候需要属性绑定v-bind:,通过props中的属性将数据传递给子组件

v-bind绑定的是形参,绑定后面的值是实参。实参的值需要通过props给子组件传值

组件内props中的数据是只读的,如果需要对传入值进行修改需要重新定义变量接收

组件内data中数据是可读可写的

反向传值($emit)

子组件向父组件传值,使用的是事件绑定机制v-on:,通过$emit()方法向父组件传递方法

可以理解为,组件通过自定义事件远程调用vue中的方法来实现方法的调用

组件中的data函数

一般情况下我们将组件私有的数据放在data中,组件中的data必须是函数方法,方法中return一个对象

在日常开发中,由于组件是可以重复使用的,所以会共用一个data,因此在引用组件的时候,我们要根据不同的环境,判断是否需要单独创建数据。data内部中return是为了保证数据的独立性而存在的

4.动态切换组件

1.v-if

2.component中的:is属性

当某些特定标签中使用组件,会无法被浏览器解析,导致dom渲染错误。所以使用component的is属性,能让自定义元素在已有的html标签被正确解析

路由

前端路由:通过URL中的hash(#号)来实现不同页面之间的切换,hash是实现单页面程序页面跳转的主要方式

1.添加路由

1.定义路由的组件

2.定义路由,并且将定义的路由影射到对应的组件

3.创建router实例,配置需要的路由

4.在new vue中挂载

点击过的导航链接都会加上样式 class ="router-link-exact-active router-link-active"

2.实现路由

1.使用组件实现<router-link to=''/xxxx">

2.路由出口,组件在路由注册,路由在vue注册

页面跳转的原理

改变url,路由监听到·url的改变,在路由规则中匹配,如果匹配到就展示component组件,组件在router-view中用于页面展示出来

3.路由传参

1.使用query。

2.使用params。

children实现子路由

同时需要注意,子路由的path不要带/(斜线),否则URL永远以根路径开始请求,不翻边我们去读URL地址

命名路由实现布局

重新定义路由规则components,这里的component加s。其中defaul是默认路径,再配置其他路径。给router-view加name属性,指定路径

嵌套路由,传递参数。

绑定的方式传递参数:

1.v-bind绑定

2.router中path接收

3.使用$router.params获得

组件的方式传递参数:props解耦合

指令

常见的指令

v-cloak:处理标签闪烁,当没有获取值的时候不显示,避免标签展示出来

v-text:输出文本

v-bind:属性类型或者内联样式class、style(用于绑定vue中的属性)

v-if:判断表达式ture或false,是否展示

v-on:处理按钮交互的监听事件

v-html:获取输出html的元素

v-model:更新元素。处理表单交互上的双向数据绑定,根据表单上的值自动更新绑定的元素值

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>

1. 负责绑定属性和样式

v-bind:class 必要的时候我们通过绑定属性或对象

v-bind:style 内联样式,通过style属性来设置样式; 外部样式,通过标签设置样式

2. 负责@click事件

.self和.stop的区别?

self只是阻止自己的事件,stop阻止自己的父级事件冒泡

.prevent:阻止表单类默认事件

.once:事件执行一次

.capture:捕获机制反向冒泡,为了保证从外到里,capture需要定义在外层

.stop:阻止冒泡事件

.self:阻止当前事件

事件修饰符可以串联,也就是可以同时使用

注意:对应的还有按键修饰符,触发键盘的事件。同时也可以自定义按键修饰符的内容

3. 负责双向数据绑定

v-bind只能实现数据的单向绑定

v-model只能在表单中使用,可以实现表单元素和model中的双向数据绑定

4. 负责循环

循环数组

循环对象数组

循环纯对象

迭代数字

v-for中的v-bind:key属性:指定唯一性对象

key 只能指定number/string类型来获取对应的对象或值

5. v-if和v-show处理判断条件

v-if每次都会重新删除渲染,有较高的切换性能消耗

v-show只会创建一次,通过添加删除display:none来处理,有较高的初始渲染消耗

6.自定义指令

定义全局的指令的写法:

Vue.directive('指令名', {对象})

目的是获取标签元素,通过插入dom和绑定,来实现自定义指令

过滤器 filters

我把它理解为状态函数,可以理解为通过传入不同的参数,得到不同的值。它的好处是不需要把过多的对数据的判断,留在html标签中。

过滤器可以多次调用,按顺序一次从前往后调用,用管道符号表示。

过滤器第一个参数作为过滤器的首个参数,过滤器本身可以自带参数

{a | b | c('ff')}//过滤器b的首参为a,过滤器c的首参为a,同时它还自带一个参数ff。a仅仅作为后面过滤器的参数而已,b和c为过滤器的名称

过滤器写法//
Vue.filter('c', function (xx) {} )

全局过滤器:所有的vue对象实例都可以共享

私有过滤器:在vue内部定义的filters,只提供当前vue使用。如果私有过滤器和全局过滤器名称一致,首先调用私有的。

生命周期

1.创建

当我们新建一个vue实例

beforeCreate

在beforeCreate生命周期函数执行的时候,data(),methods()还未初始化

created

在created执行的时候,data(),methods()已经初始化成功了

当我们此时开始编译模版

beforeMount

在beforeMount执行的时候,模版已经在内存中编辑完成,但没有渲染到页面中

mounted

在mounted执行的时候,内存中模版已经挂载完毕,可以看到最新渲染的页面效果(用来加载ajax相关请求)

mounted执行完成,vue的实例也对应的创建完成。如果需要对dom操作,需要在mounted生命周期函数中处理

2.运行

是否需要虚拟dom

beforeUpdate

当数据更新时调用,此时页面尚未同步,不考虑页面的dom渲染

当data中新的数据,重新渲染一份到内存中的dom树中

updated

在执行updated函数的时候,我们的dom渲染已经完成。

页面渲染和data数据已同步。

3.销毁

beforeDestroy

在执行beforeDestroy生命周期函数的时候,vue实例准备进入销毁阶段

destoryed

在执行函数的时候,表示已经销毁,vue实例的所有指令不可用,事件和数据被移除

vuex

通过组件间相互传值的方式麻烦而且也易出错,如果使用一个公共的仓库,来管理存储数据,仓库中的数据对于所有组件都可以共享,并且仓库中数据更新会及时自动的改变组件中使用的数据结果,这里就避开了多个组件间传值的负责数据逻辑。

而vuex的核心就是一个仓库用于管理数据状态,store是一个具体的容器,每个应用仅仅包含一个store实例。我们用到的公共数据,交给vuex统一管理,综上所示,vuex是确保组件的数据存在一致性的解决方案。

最简单的Store

我们可以通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更。

核心概念

需要再ES6的对象中添加注册store属性,并在state文件中初始化Vuex。

(1)state:存放并取得数据

this.$store.state

(2)mutation:同步处理,修改数据

store.commit('count', 10)

(3)action:可做异步处理,需要提交mutation修改数据

(4)getter:对数据处理后,取得数据

属性访问:store.getters.doneTodos
方法访问:store.getters.getTodoById(2)

(5)module:区分模块化store

使用辅助函数

import { mapState, mapGetters } from 'vuex'
export default {
  computed:
  // 映射 this.count 为 store.state.count
  ...mapState(['count']),
  // 
  ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ]),
  // 
  ...mapMutations(['setcount'])
}

总结思路:其实vue的核心就是拆分组件,将功能独立成一个个组件,而整个页面也是一个组件,通过路由实现页面的切换,store完成对本地数据的管理,指令所包含的就是事件语法部分,以上条件,创造了一个动态的vue项目,当然一个完整的项目还不仅仅是这些,由于时间有限目前只整理出来了这些内容,也欢迎同好交流学习。