Vue-cli 2.0 总结
写了很久了,一直没有发出来,本来想像Vue那样分知识点一个一个讲的,但是Vue-cli其实也就是一个脚手架,所以索性合在一起讲
写一下一直以来对Vue的理解
什么是Vue?为什么选择Vue?
简单的来说,Vue就是一个渐进式框架
+ MVVM模式
那么问题来了,什么是 渐进式框架?
渐进式框架
总结一句话来说,可以只使用一部分功能,不必使用全部功能,可以跟其他的框架结合使用,这就叫渐进式框架.
每个框架都有一定的主张,(会有自己的一些特点),从而会对使用者有一定的要求,相比较于Angular的模块机制和依赖注入,react的函数式编程等,Vue的主张是最少
它可以在原项目的基础上,拆分出一两个组件用vue来封装,其他的继续用jquer或者javascript,也可以使用Vue-cli来搭建全家桶
再来看看什么是 MVVM设计模式
MVVM模式
其实Vue设计上没有完全遵循MVVM模式,但是Vue的设计无疑是受到了它的启发
MVVM分来三个模型
- M: model 数据模型
- V: view 视图模型
- VM: 视图数据模型
相比较于传统H5的MVC模式,MVVM模式将应用程序分为了三大部分,实现了职责分离,通过数据双向绑定
让数据驱动视图.
在学习Vue的过程中要转化思想,不要想着怎么操作DOM元素,而是操作数据
以后再介绍Vue-cli 3.0的版本,我们先在Vue-cli 2.0的基础上,看看Vue给我们带来了哪些功能, 想要了解在html中使用Vue.js的用法,可以搜索我的博客 陈先生的小前端
在学习Vue的过程中,我们没必要一上来就搞懂Vue的每一个部件和功能,先从核心功能开始学习,逐渐扩展。
同时,在使用中,我们也没有必要把全部件能都拿出来,需要什么就用什么就是了。
搭建Vue-cli
项目是运行在node环境上的,所以我们需要去Node官网下载安装
由于Vue-cli是基于webpack的,所以我们要再安装一下webpack npm install webpack -g
。
全局安装 npm install vue-cli -g
初始化项目 vue init webpack project
过程我就不细说了,直接看看项目结构
Vue基础语法
插值
- 数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值
- v-once 能执行一次性地插值,当数据改变时,插值处的内容不会更新。
- v-text 和双大括号一样,绑定一个值
- v-html 简单的来说能编译标签,站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致XSS攻击。
指令
- 解释:指令(Directives)是带有 v- 前缀的特殊属性。指令属性的值预期是单个 JavaScript 表达式 (v-for 是例外情况)
- 作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
刚刚说到的 v-html 那些也是指令,就不再重复解释了,看看我们还经常用到那些指令
v-bind
- 作用:绑定属性,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
- 语法:v-bind:title=”msg”
- 简写::title=”msg”
1 | <!-- 完整语法 --> |
v-on
- 作用:绑定事件
- 语法:v-on:click=”say” or v-on:click=”say(‘参数’, $event)”
- 简写:@click=”say”
- 说明:绑定的事件定义在methods
1 | <!-- 完整语法 --> |
绑定事件后面还可以跟一些修饰符,修饰符在一些应用场景可以起关键作用,类似阻止冒泡之类的,看看都有哪些事件修饰符(还有其他类型的修饰符)
- .native 原生点击事件
- .stop 阻止冒泡,调用 event.stopPropagation()
- .prevent 阻止默认行为,调用 event.preventDefault()
- .capture 添加事件侦听器时使用事件捕获模式
- .self 只当事件在该元素本身(比如不是子元素)触发时,才会触发事件
- .once 事件只触发一次
主要要注意的是,修饰符可以串联使用,不过要注意前后关系(用 @click.prevent.self 会阻止所有的点击,而 @click.self.prevent 只会阻止元素上的点击。)
为什么在 HTML 中监听事件?
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
修饰符一共有哪些种类呢?
- 事件修饰符: 就是上面讲的那些
- 按键修饰符: 针对键盘keyup的修饰符
- 系统修饰符: 按下相应按键时才触发鼠标或键盘事件的监听器。
- 表单修饰符: 多用于表单
- .lazy : v-model 在每次 input 事件触发后将输入框的值与数据进行同步。你可以添加 lazy 修饰符,从而转变为使用 change
- .number : 如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符
- .trim : 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符
- 自定义事件修饰符: .sync, 后面会讲到怎么用
v-model
- 作用:在表单元素上创建双向数据绑定
- 说明:监听用户的输入事件以更新数据,多用于表单中
v-for
- 作用:基于源数据多次渲染元素或模板块
v-if , v-show
这两个都是用于条件渲染
- v-if:根据表达式的值的真假条件,销毁或重建元素
- v-show:根据表达式之真假值,切换元素的 display CSS 属性
所以如果需要频繁的切换显示状态,使用v-show对性能更友好
v-pre
- 说明:vue会跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
自定义指令
如果觉得vue自带的指令不够用,我们可以进行自定义指令
1 | // 输入框自动获取焦点 |
script内的方法
1 | export default { |
data
data大家都知道里面存放的是数据,可是为什么需要一个return返回?
因为不使用return包裹的数据会在项目的全局可见,会造成变量污染
使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。
methods
用来存放方法,我们所有的方法都尽量写在里面,便于管理
computed(计算属性)
- 说明:计算属性是基于它们的依赖进行缓存的,只有在它的依赖发生改变时才会重新求值
- 注意:computed中的属性不能与data中的属性同名,否则会报错
为什么会用到计算属性呢? 因为在模板中放入太多的逻辑会让模板过重且难以维护,举个例子
1 | <div id="example"> |
想要反转字符串,但是这样写显然让人觉得看的很累,所以采用计算属性来写
1 | <div id="example"> |
其实写在methods也可以实现这个功能,采用计算属性就是为了响应式依赖进行计算,对性能更友好
watch(监听)
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
1 | watch:{ //watch 观察,可以指定观察的属性(数据),属性一旦发生改变,就会调用观察所对应属性的 函数 |
过滤器
讲一下vue中的过滤器,说到过滤器,先说一下vue中双大括号
, 它也是单个 JavaScript 表达式,所以可以使用过滤器
- 作用:文本数据格式化
- 过滤器可以用在两个地方:
双大括号
和 v-bind 表达式 - 两种过滤器:1 全局过滤器 2 局部过滤器
过滤器可以串联,可以接收多个参数
给个简单的例子
1 | <div id="app"> |
components(组件)
当引入组件的时候需要在这边声明,具体后面再说
生命周期
每个 Vue 实例在被创建之前都要经过一系列的初始化过程。
例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。
同时在这个过程中也会运行一些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。
- 创建之前: beforeCreate
- 说明:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
- 注意:此时,无法获取 data中的数据、methods中的方法
- 创建之后: created –>一般在这个时候进行请求数据
- 注意:这是一个常用的生命周期,可以调用methods中的方法、改变data中的数据
- 使用场景:发送请求获取数据
- 组件挂载之前: beforeMount –>在组件挂载完成之前,组件还没有创建完成,模板还没有生成
- 说明:在挂载开始之前被调用
- 组件挂载之后(所有组件挂载完成): mounted –>生成模板,获取模板内容
- 说明:此时,vue实例已经挂载到页面中,可以获取到el中的DOM元素,进行DOM操作
- 组件更新之前: beforeUpdate
- 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
- 注意:此处获取的数据是更新后的数据,但是获取页面中的DOM元素是更新之前的
- 组件更新之后: updated
- 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
- 组件销毁之前: beforeDestroy –> this.$refs.com1.$destroy();
- 说明:实例销毁之前调用。在这一步,实例仍然完全可用。
- 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等
- 组件销毁之后: destroyed
- 说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
组件的使用
组件一般分为两种,父子间组件和非父子间组件..只要弄清楚传值,监听和发送,就差不多掌握了
创建组件
首先创建一个.vue的页面,作为一个组件
在需要它的页面导入 import 组件名 from '@/components/页面名称.vue'
之后在 components: { 组件名 }
中声明一下就可以调用了
prop传值
我们先看看父组件怎么传值给子组件
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
为什么要用prop?因为组件实例的作用域是独立的,子组件的模板不能直接使用父类的,所以Vue中使用prop进行父级向子级传值
- 方式:通过子组件props属性来传递数据 props是一个数组
- 注意:属性的值必须在组件中通过props属性显示指定,否则,不会生效
- 说明:传递过来的props属性的用法与data属性的用法相同
假设这个是我们要创建的组件
1 | <template> |
需要注意的是,在子组件中不可以修改prop传递过来的值
每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。
在两种情况下,我们很容易忍不住想去修改 prop 中数据:
- Prop 作为初始值传入后,子组件想把它当作局部数据来用;
- Prop 作为原始数据传入,由子组件处理成其它数据输出。
所以我们需要一个字段去接收
还有一个重点我们要讲一下, JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
那么问题来了,非prop属性会被替换吗
举个很简单的例子,一个组件里面定义了class,在外面引用该组件时,也写了一个class,class会被替换吗
庆幸的是,class 和 style 特性会稍微智能一些,即两边的值会被合并起来
所以我们需要使用 inheritAttrs: false
来禁用特性继承,配合$attrs
1 | <p v-bind="$attrs">继承属性</p> |
自定义事件
子组件传值给父组件就需要用到自定义事件,自定义事件大体上分为三个步骤,我把它叫做三步曲
第一步:监听自定义事件
1 | <!-- 父组件接受子组件的to-parent方法 --> |
第二步:触发自定义事件
1 | methods:{ |
第三步:传递过来的值进行计算
1 | methods: { |
现在有一个问题,如果子组件只是想当初的修改一下父组件传进来的值,并且赋值给父组件,怎么办
使用修饰符 sync
举个例子
1 | <template> |
动态效果如下:
vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。这里用sync实现,只是给大家提供一个思路,让其明白他的实现原理,可能有其它复杂的功能适用sync。
到这里最常用的父子组件相互传值就已经完成了,接下来说一下非父子间的传值
bus中央线
其实原理和自定义事件是一样的,也是三部曲
第一步
创建一个 vue 作为中央线来处理 非父子关系的组件传递数据
1 | import Vue from 'Vue' |
第二步
在组件二中创建监听事件—-注意:监听事件一定要在发射之前,监听才有效
1 | //使用前先导入 |
第三步
在组件一中发射组件
1 | add(){ |
插槽
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 元素作为原始内容的插槽。
在组件中写 slot,想要几个就写几个
1 | <div> |
使用插槽
1 | <div id="app"> |
现在这种用法虽然也可以,但是2.6.0
v-slot 指令取代了 slot,并且只能在template上使用
1 | <template v-slot:title>我是一个标题</template> |
混入 (mixin)
有时候不需要插槽的功能,我们需要实现Vue 组件中的可复用功能,比如三个组件中都需要共同的方法,我们就可以用到mixin
新建一个mixin.js
1 | var mixin = { |
之后在组件中导入使用
1 | import mixin from '@/util/mixin.js' |
需要注意的是
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
router路由
说到路由,先说一下为什么vue中的路由,在安卓或者ios监听不到页面url的变化,因为它是一个单页应用程序
SPA -单页应用程序
单页Web应用(single page application,SPA),就是只有一个Web页面的应用,是加载单个HTML页面,并在用户与应用程序交互时动态更新该页面的Web应用程序。
单页面应用程序: 只有第一次会加载页面, 以后的每次请求, 仅仅是获取必要的数据.然后, 由页面中js解析获取的数据, 展示在页面中
传统多页面应用程序:对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面
优势
- 减少了请求体积,加快页面响应速度,降低了对服务器的压力
- 更好的用户体验,让用户在web app感受native app的流畅
实现思路和技术点
- 锚点的使用(window.location.hash #)
- hashchange 事件 window.addEventListener(“hashchange”,function () {})
- 监听锚点值变化的事件,根据不同的锚点值,请求相应的数据
- 原本用作页面内部进行跳转,定位并展示相应的内容
路由的使用
SPA往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生,当URL中的哈希值(# hash)发生改变后,路由会根据制定好的规则,展示对应的视图内容
在router/index.js 中配置路由
1 | export default new Router({ |
在页面中使用编程式导航
1 | // 字符串 |
router.replace
router.replace 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
路由守卫
具体的不说了,简单介绍一下完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
Vuex数据仓库
vuex是vue的一个插件,是一个专为 Vue.js 应用程序开发的状态管理模式。(状态:数据,改变数据和获取数据)
axios
由于vue不再继续维护vue-resource,并推荐使用 axios,所有axios进入了大家的视野
- 以Promise为基础的HTTP客户端,适用于:浏览器和node.js
- 封装ajax,用来发送请求,异步获取数据
- 从浏览器中创建 XMLHttpRequest
- 从 node.js 发出 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防止 CSRF/XSRF
安装:npm i -S axios
使用
1 | // 在浏览器中使用,直接引入js文件使用下面的GET/POST请求方式即可 |
看看具体的代码实现
Get 请求
1 | const url = 'http://vue.studyit.io/api/getnewslist' |
Post 请求
默认情况下,axios 会将JS对象序列化为JSON对象。为了使用 application/x-www-form-urlencoded 格式发送请求,我们可以这样:
1 | // 使用 qs 包,处理将对象序列化为字符串 |
如果就是正常的传递json对象,那就这样
1 | axios.post('/user', { |
打包
项目做好后,最后一步就是打包了
打包其实vue-cli都帮我们配置好了,npm run build
就可以了,需要其他的配置,以后会说到