- 嵌入原生app
// 返回键事件放到原型和wiodow 能被原生APP调用
Vue.prototype.backnative = window['backnative'] = function () {
if (this.$store.state.userAng == 'android') {
console.log('android回退')
/* eslint-disable */
$android.backnative()
} else if (this.$store.state.userAng == 'iphone') {
console.log('iphone回退')
/* eslint-disable */
window.webkit.messageHandlers.backnative.postMessage({})
}
}
- 搜索
searchData() {
let keyword = this.keyword
if (keyword) {
return this.member.filter(function(realname) {
return Object.keys(realname).some(function(key) {
return (
String(realname[key])
.toLowerCase()
.indexOf(keyword) > -1
)
})
})
}
return this.member
}
- APP.vue 适配
<script>
export default {
name: 'App',
methods: {
fit() {
var docEl = document.documentElement
var resizeEvt =
'orientationchange' in window ? 'orientationchange' : 'resize'
var recalc = function() {
var clientWidth = docEl.clientWidth
if (!clientWidth) return
if (clientWidth >= 750) {
docEl.style.fontSize = '100px'
} else {
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px'
}
// console.log('<750', clientWidth, docEl.style.fontSize);
}
if (!document.addEventListener) return
window.addEventListener(resizeEvt, recalc, false)
// DOMContentLoaded->dom加载完就执行,onload要dom/css/js都加载完才执行
document.addEventListener('DOMContentLoaded', recalc, false)
}
},
created() {
this.fit()
var ua = navigator.userAgent.toLowerCase()
if (/iphone|ipad|ipod/.test(ua)) {
this.$store.commit('setuserAng', 'iphone')
} else if (/android/.test(ua)) {
this.$store.commit('setuserAng', 'android')
}
}
}
</script>
- 测试环境要代理,打包到服务器改路径
const service = axios.create({
baseURL: '/api',
timeout: 5000 // 超时
});
// config/index.js
// dev
proxyTable: {
'/api': {
target: 'https://xxx',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
// build
assetsPublicPath: './',
// 图片地址build/utils.js
publicPath:'../../'。
// 手机端
<meta name="viewport"
content="height=device-height,width=device-width,
initial-scale=1.0 maximum-scale=1.0,
minimum-scale=1.0 user-scalable=0">
生命周期
beforeCreate
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created
在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount
在挂载开始之前被调用:相关的 render 函数首次被调用。
该钩子在服务器端渲染期间不被调用。
mounted
el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted:
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
该钩子在服务器端渲染期间不被调用。
beforeUpdate
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick 替换掉 updated:
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
该钩子在服务器端渲染期间不被调用。
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。
该钩子在服务器端渲染期间不被调用。
destroyed
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
该钩子在服务器端渲染期间不被调用。
计算属性中不能用ref
created()组件创建后,数据初始化。但dom未生成
mounted() 数据装在dom上用this.refs.xxx.方法操作dom
如何实现数据双向绑定?
Object.definePrototype
vue.js中数据(data)为何是函数形式?需要return?
因为不使用return包裹的数据会在项目的全局可见,会造成变量污染 使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。 Object是引用数据类型,如果不用function 返回,每个组件的data 都是内存的同一个地址,一个数据改变了其他也改变了; javascipt只有函数构成作用域(注意理解作用域,只有函数的{}构成作用域,对象的{}以及 if(){}都不构成作用域),data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响
简单阐述一下vue的生命周期
beforeCreate、created、 beforeMount、mounted、
beforeUpdate、updated、 beforeDestroy、destroyed
钩子函数,其实和回调是一个概念,当系统执行到某处时,检查是否有hook,有则回调。说的更直白一点,每个组件都有属性,方法和事件。所有的生命周期都归于事件,在某个时刻自动执行。
创建前/后: 在beforeCreate阶段,vue实例的挂载元素el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
首先需要创建一个实例,也就是在 new Vue ( ) 的对象过程当中,首先执行了init(init是vue组件里面默认去执行的),在init的过程当中首先调用了beforeCreate,然后在injections(注射)和reactivity(反应性)的时候,它会再去调用created。所以在init的时候,事件已经调用了,我们在beforeCreate的时候千万不要去修改data里面赋值的数据,最早也要放在created里面去做(添加一些行为)。
当created完成之后,它会去判断instance(实例)里面是否含有“el”option(选项),如果没有的话,它会调用vm.$mount(el)这个方法,然后执行下一步;如果有的话,直接执行下一步。紧接着会判断是否含有“template”这个选项,如果有的话,它会把template解析成一个render function ,这是一个template编译的过程,结果是解析成了render函数:
使用render函数的结果和我们之前使用template解析出来的结果是一样的。render函数是发生在beforeMount和mounted之间的,这也从侧面说明了,在beforeMount的时候,$el还只是我们在HTML里面写的节点,然后到mounted的时候,它就把渲染出来的内容挂载到了DOM节点上。这中间的过程其实是执行了render function的内容。
在使用.vue文件开发的过程当中,我们在里面写了template模板,在经过了vue-loader的处理之后,就变成了render function,最终放到了vue-loader解析过的文件里面。这样做有什么好处呢?原因是由于在解析template变成render function的过程,是一个非常耗时的过程,vue-loader帮我们处理了这些内容之后,当我们在页面上执行vue代码的时候,效率会变得更高。
beforeMount在有了render function的时候才会执行,当执行完render function之后,就会调用mounted这个钩子,在mounted挂载完毕之后,这个实例就算是走完流程了。
后续的钩子函数执行的过程都是需要外部的触发才会执行。比如说有数据的变化,会调用beforeUpdate,然后经过Virtual DOM,最后updated更新完毕。当组件被销毁的时候,它会调用beforeDestory,以及destoryed。
如何实现一个自定义组件
第一步:在components目录新建你的组件文件(indexPage.vue),script一定要export default {}
第二步:在需要用的页面(组件)中导入:import indexPage from '@/components/indexPage.vue'
第三步:注入到vue的子组件的components属性上面,components:{indexPage}
第四步:在template视图view中使用,
问题有indexPage命名,使用的时候则index-page。
不同组件之间如何通信的?
1.父子组件
//父组件通过标签上面定义传值 //子组件通过props方法接受数据
//子组件通过$emit方法传递参数
2.不同组件
bus.$emit('id-selected', 1)
// 组件B
bus.$on('id-selected', function (id) {
console.log(id)
})
3.复杂逻辑
vuex有四个核心概念,其中state和getters主要是用于数据的存储与输出,
而mutations和actions是用于提交事件并修改state中的数据。
nextTick和Vuex两个有没有用过,分为什么情况下用到?
vue框架中状态管理。在main.js引入store,注入。新建了一个目录store,….. export 。场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
vuex
$store.commit()方法来更改状态
getteers相当于vue中computed计算属性,可以对数据进行加工和过滤
actions是异步的改变state状态,而Mutations是同步改变状态。
vuex 严格模式,有啥问题。 严格模式下,不是有mutation函数引起的状态变化都会抛出错误。这保证了状态变更都能被调试工具跟踪到。 不要再发布环境下启用严格模式,严格模式会深度监测状态树来检测不合规的状态变化,请确保发布环境下关闭严格模式,以避免性能损失。 表单的v-model属性值是Vuex的state时,如果严格模式,因为用户输入时,v-model会试图修改v-model的值,由于修改并非mutation执行的,严格模式下会抛出错误。参考这里 针对这种情况,有两个处理方法:一个是双向绑定的计算属性,一个是给表单绑定value,然后侦听input或change事件,在事件中调用action
vue-router
声明式(标签跳转)
<router-link :to="index">
编程式( js跳转)
router.push('index')
Vue的响应式原理你知道是怎么实现的吗?你觉得订阅者-发布者模式和观察者模式有区别吗?
前端路由 怎么实现路由的嵌套?
路由是根据不同的 url 地址展示不同的内容或页面。
前端的路由都是通过 hash 来实现的,hash 能兼容低版本的浏览器。
如果我们把上面例子中提到的 3 个页面用 hash 来实现的话,它的 URI 规则中需要带上 #。
1 http://10.0.0.1/
2 http://10.0.0.1/#/about
3 http://10.0.0.1/#/concat
Web 服务并不会解析 hash,也就是说 # 后的内容 Web 服务都会自动忽略,
但是 JavaScript 是可以通过 window.location.hash 读取到的,
读取到路径加以解析之后就可以响应不同路径的逻辑处理。
history 是 HTML5 才有的新 API,可以用来操作浏览器的 session history。
基于 history 来实现的路由可以和最初的例子中提到的路径规则一样。
前端路由更多用在单页应用上,不是vue-router
MVVM
MVVM是Model-View-ViewModel的缩写。mvvm是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。 mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到View。
vue如何实现按需加载配合webpack设置?
webpack中提供了require.ensure()来实现按需加载。
以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:
import home from '../../common/home.vue'
进行页面按需加载的引入方式:
const home = r => require.ensure( [], () => r (require('../../common/home.vue')))
c
vue-loader是webpack的一个loader,用于处理.vue文件。 .vue 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue 文件包含三种类型的顶级语言块 <template>、<script>和 <style>。
vue-loader 会解析文件,提取每个语言块,如有必要会通过其它 loader 处理(比如<script>默认用babel-loader处理,<style>默认用style-loader处理),最后将他们组装成一个 CommonJS 模块,module.exports 出一个 Vue.js 组件对象。
vue-loader 支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 lang 属性。例如,你可以像下面这样使用 Sass 语法编写样式: