独立构建VS运行时构建
- 两者区别,独立构建包含模板编译器。模板编译是将编译vue模板字符串成纯js渲染函数,若想用template,则需要编译。
独立构建
- 独立构建包含模板编译器并支持template选项。他也依赖于浏览器接口的存在,所以你不能用其来为服务器渲染。
运行时构建
运行时构建不包含模板编译器,只能用render选项但即使使用运行时构建,在单文件组件中也依然可以写模板,因为单文件组件的模板会在构建时预编译为render函数。运行时构建要比独立构建轻量30%;
默认npm导出的包是运行时构建。为使用独立构建在webpack配置中添加以下别名
1
2
3
4
5resolve:{
alias:{
'vue$':'vue/dist/vue.js'
}
}不要用import Vue from ‘vue/dist/vue.js’-用一些工具或第三方工具库引入Vue,这可能导致应用程序在同一加载运行时和独立构建并造成错误。
数据劫持
- 核心方法是通过Object.definedProperty()来实现对属性进行劫持,达到监听数据变动的目的。
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
数据绑定原理
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 ),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
组件传值
父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;
数据绑定
- 实现mvvm双向绑定需实现以下几点:
1 | 1.实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者。 |
- 我们知道可以利用
Obeject.defineProperty()
来监听属性变动
那么将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter
和getter
这样的话,给这个对象的某个值赋值,就会触发setter
,那么就能监听到了数据变化。。相关代码可以是这样:
1 | let data = {name: 'kindom'}; |
实现编译
- compile主要的工作是解析模板指令,将模板指令替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知更新视图。
introction
- vue是一套构建用户的渐进式框架。与其他重量级框架不同,vue采用自底向上增量开发的设计。
- 指令带有v-,以表示它们是Vue.js提供的特殊属性,他们会在渲染过的DOM上应用特殊的响应式行为。
- 计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter ,且计算属性是基于他的依赖缓存的。
v-if VS v-show
- v-if是真实的条件渲染,因为他会确保条件快在切换当中适当的销毁与重建。若初始条件为假时,则什么也不会做,仅在第一次变为真时才开始局部编译(编译会被缓存起来)。
- 相比之下, v-show 简单得多——元素始终被编译并保留,只是简单地基于 CSS 切换。
- 一般来说, v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换使用 v-show 较好,如果在运行时条件不大可能改变则使用 v-if 较好。
修饰符
- .lazy:默认情况下,v-model在input事件中的同步框的值和数据,但你可以添加一个修饰符lazy,从而转变在change事件中同步。
- .number
- .trim
组件
Vue.component(tagName,options)
DOM模板解析说明:当DOM作为模板时,会受到一些HTML的一些限制,因为在Vue只有在浏览器解析和标准化HTML后才能获取模板内容。即table的子标签只能是tr,故需要is来指定。
1
2
3<table>
<tr is="my-row"></tr>
</table>组件中的data必须是一个函数使每个组件中的数据引用都有一个自己的作用域,不会互相影响。
父传子:使用props传递数据。组件实例的作用域是孤立的即子组件的模版内不能直接引用父组件的数据。
子传父:通过自定义事件$emit
非父子组件通信
1
2
3
4
5
6
7var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})
深入响应式原理
如何跟踪变化
把一个普通js对象传给Vue实例来作为他的data选项,Vue将遍历它的属性,用Object.defineProperty将它们转为getting/setting。这是ES5的特性,不能打补丁实现,这便是为什么Vue不支持IE8及以下版本的原因。
用户看不到getting/setting,但在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。这里需要注意的是浏览器控制台在打印对象时getting/setting的格式化并不同,可通过vue-devtools
来获取更加友好地检查接口。
每个组件实例都有watcher程序实例,他会在渲染的过程中把属性记录为依赖,之后当依赖项的setting被调用时,就会通知watcher重新计算,从而使和它相关联的组件得以更新。
变化检测问题
受现在的js影响,vue不能检测到对象的属性的添加或删除。因为Vue在初始化实例时将属性转为getting/setting,所以必须在data对象上在能让Vue转换它,这样才能是响应的。那种`vm.a=2’不是响应式的,因为js边解释边执行,不可能在初始化时将2付给a
Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive properties)。然而它可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上:
您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
1
2
3Vue.set(vm.someObject, 'b', 2)
this.$set(this.someObject,'b',2)有时你想向已有对象上添加一些属性,例如使用Object.assign()或_.extend()方法来添加属性。但是,新添加到对象上的新属性不会被触发更新,这种情况下可可创建一个新的对象,让它包含原对象的属性和新对象属性。
1 | //代替Object.assign(this.somObject,{a:1,b:2}) |
- 如果不在data中声明message,则message不是一个响应式的,同时Vue将发出警告表明你的渲染方法正试图访问一个不存在的属性。因为在依赖项跟踪系统中,他消除了一类边界情况,也使Vue实例在检查系统的帮助下运行的更高效。在代码可维护方面上这一点很重要:data对象就像组件状态的模式,在它上面声明的所有属性让组织代码更易于被其他开发者或是自己回头重新阅读加速理解。
异步更新队列
- Vue执行DOM更新是异步的,只要观察到数据变化,Vue就开始一个队列,将同一事件循环内的所有的数据变化缓存起来。如果watch被多次触发,只会推入一次到队列中。然后再接下来循环中,Vue刷新队列并仅执行必要的DOM更新。
过渡效果
- 元素封装成过渡组件后,在遇到删除或添加时,Vue将
- 自动嗅探到目标元素是否有CSS过渡或动画,并在合适时添加或删除CSS类名。
- 如果过渡组件设置了过渡的js钩子函数会在相应的阶段调用钩子函数。
- 如果没有找到js钩子也无css动画,DOM操作在下一帧立即执行。(注:此指浏览器逐帧动画机制,与Vue及其nextTick概念不同)
- 当只用js过渡时,在enter和leave中,回调函数done是必须的。否则,他们会被同步调用,过渡立即完成。推荐对于仅使用js过渡的元素添加
:css="false"
,Vue会跳过CSS的检测,这也是避免过渡过程中CSS的影响。
组件传值
非父子组件间传值
单独的事件中心管理组件间的通信
var eventHub = new Vue()
监听事件与销毁事件
1
2eventHub.$on('事件名称',触发的事件)
eventHub.$off('事件名称')触发事件
eventHub.$emit('事件名称',数据)
- 新建一个js文件,然后引入vue,实例化vue,最后暴露该实例。
- 在要广播的地方引入定义好的实例。
- 通过ViewEvent.$emit(‘名称’,’数据’)
- 在要接收的地方通过ViewEvent.on(‘名称’,function(){}),同时可通过
$event
获取到传过来的数据。
1 | //新建ViewEvent.js文件 |
父子组件
- 利用在父组件中的html标签中定义ref属性,通过$refs获取子组件的dom节点进行操作。
- 利用$parents获取父组件的数据。
- 父组件可通过
$event
得到子组件中的信息
子组件通过自定义事件向父组件传递信息
1 | <button @click='$emit("enlarge-text",0.1)'>扩大字体</button> |
父组件监听子组件的事件
1 | <menu-item @enlarge-text='fontSize += $event'></menu-item> |
props
- 除了自定义数据可传外,还可将this或方法(不可加括号)
vue路由配置
安装
npm install vue-router --save
/cnpm install vue-router --save
在main.js文件中引入并使用VueRouter
import VueRouter from vue-router
Vue.use(VueRouter)
配置路由
创建组件,引入组件
定义路由
1
2
3
4const routes = {
{path: '/bar',component: Bar},
{path: '/foo',component: Foo}
}实例化VueRouter
1
2
3const router = new VueRouter({
routes
})挂载
1
2
3
4new Vue({
el: '#app',
router
})在跟组件中加
<router-view></router-view>
webpack.config配置
当以命令行形式命令运行webpack或webpack-dev-server时,工具会发现我们并没有提供要打包的文件的入口和出口文件,此时他会检查项目根目录中的配置文件并读取这个文件就拿到了导出的这个配置对象,然后根据这个对象,进行打包。
1
2
3
4
5
6
7
8
9//在内存中,根据指定的模板页面生成一份内存中的首页,同时把自动打包好的bundle.js文件注入到页面底部
const htmlWebpackPlugin = require('html-webpack-plugin')
//在输出对象中的plugins(是webpack插件的配置节点)数组中配置节点
plugins:[
new htmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'), //指定模板文件路径
filename:'index.html' //设置生成的内存页面的名称
})
]配置第三方loader模块
1 | //下载相应的包 |
- 默认情况下,webpack无法处理css文件中的url地址,不管是图片还是字体库,只要是url地址都处理不了。
1 | cnpm i url-loader file-loader -D |
语法转换(高 ——> 低)
在webpack中。默认只能处理一部分ES6新语法,一些更高级ES6语法或ES7语法,webpack是处理不了的,这时就需要借助第三方loader来帮助webpack处理这些高级语法,当第三方loader把高级语法转为低级语法后,会将结果交给webpack去打包到main.js中。
通过Babel,可将高级语法转为低级语法
- 安装包
1
2cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
cnpm i babel-preset-env babel-preset-stage-0 -D打开webpack的配置文件,在module节点下的rules数组中添加一个新的匹配规则。
1
2
3
4{ test: /\.js$/, use:'babel-loader',exclude:/node_modules/}
注意:在配置babel的loader规则时,必须通过exclude选项将node_modules目录排除在外,原因有两:
1.不排除node_modules时,Babel会将node_modules中的所有第三方js文件都打包编译,这样非常消耗内存,同时,打包速度也非常慢。
2.哪怕最终Babel将所有node_modules中的js文件转换完毕,项目也无法正常进行。在项目根目录中新建一个叫做babelrc的Babel配置文件,这个配置文件属于JSON格式,故不可加注释,字符串需用双引号。
1
2
3
4
5在babelrc写如下配置:preset可翻译为【语法】
{
"preset": {"env":"stage-0"},
"plugins": ["transform-runtime"]
}
包查找规则
- 在webpack中尝试使用vue,即使用
import Vue from 'vue'导入的Vue构造函数,功能不完整,只提供了runtime-only的方式,并没有提供像网页那样的使用方式。
可使用import Vue from '../node_modules/vue/dist/vue.js'
- 包的使用规则
1 | 1.找项目的根目录中是否有node_modules文件夹 |
渲染组件
- 默认 webpack 无法打包 vue文件,需要安装相关的loader
1 | cnpm i vue-loader vue-template-compler -D |
- 在webpack中,如果想要通过 vue ,把一个组件渲染到页面中去展示vm实例中的render函数可实现。
- createElements是一个方法,调用它可将指定的组件模板渲染为html结构。
1 | let vm = new Vue({ |
webpack中使用vue
1 | 1.安装 vue 包,cnpm i vue -S |
注意:App这个组件是通过vm实例的render函数渲染出来的,render函数如果要渲染组件,渲染出来的组件只能放到el:‘#app’ 所指定的元素中。
Account和Goodlist组件是通过路由配置监听到的,所以这两个组件只能展示到属于路由的
加载轮播图
- 使用vue-resource获取数据。
- 使用vue-resource的this.$http.get获取数据
- 获取到的数据保存到data身上。
- 使用v-for循环渲染到每个item项。
1 | cnpm i vue-resource -D |
Promise使用
- promise本质就是解决回调地狱问题。
- Promise是一个构造函数,故可通过 new Promise() 方法得到一个 Promise的实例。
- Promise表示一个异步操作,每当我们 new 一个Promise 实例,就表示一个具体的异步操作。故内部拿到操作结果后,无法使用 return 把操作结果返回给调用者,只能通过回调函数将成功和失败结果返回给调用者。
普通读取文件方法
1 | const fs = require('fs') |
导入时间插件
1 | cnpm i moment -S |
vue-resource请求数据
1 | //设置请求的根路径 |
1 | //post请求内容及拼接数据 |
制作顶部滑动条
需要借助于 MUI 中的 tab-top-webview-main.html
需要把slider 区域 mui-fullscreen 类去掉
滑动条无法正常触发滑动,通过检查官方文档,发现这是 js 组件,需要初始化一下
1
2
3
4
5
6
7
81.导入mui.js文件
2.调用官方提供的方式去初始化
mounted(){ //调用时机会重要
mui('.mui-scroll-wrapper').scroll({
deceleration: 0.0005
//flick减速系数,系数越大,滚动速度越慢,滚动距离越小,默认为0.0006
})
}我们在初始化 滑动条时,导入的 mui.js ,但是控制台报错:因webpack打包好的bundle.js文件默认启用严格模式,故无法解析mui.js文件里的一些属性。
1
2
3
4
5
6解决方法:remove "use strict" directive
cnpm i babel-plugin-transform-remove-strict-mode -D
//在 .babelrc文件中
{
"plugins":["transform-remove-strict-mode"]
}
动画transition
当插入或删除包含在transition组件中的元素,Vue将会做以下处理
- 自动嗅探目标元素是否应用了css过渡或动画,如果是在恰当的时机添加/删除css类名。
- 如果过渡组件提供了js钩子函数,这些钩子函数将在恰当时机被调用。
- 如果没有找到js钩子并且没有检测到css过渡/动画,DOM操作*(插入/删除)在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和Vue的nextTick概念不同)
用手机调试项目
1 | "dev": "webpack-dev-server --open --port 3000 --hot --host 172.23.232.1" 连接上电脑主机 |
- 保证手机可正常运行;
- 要保证手机于开发项目的电脑处于同一个WIFI环境中,也就是说手机可以访问到 电脑的 IP
- 打开自己项目的package.json文件,添加 –host指令,把当前电脑的WIFI IP地址设置为 –host 的指令值
- 通过cmd终端运行 ‘ipconfig’ ,乍看 无线网的 ip 地址。
使用邮箱发送短信
1 | cnpm i nodemailer -D |