最近三个月来公司项目都是用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'])
}