记录一些小技巧和踩过的坑html
因为本篇文章内容太多,致使SF编辑器有点卡,因此新开辟了一篇 vue2实践(二),后续再这里更新。vue
<child1 ref="child1" msg="{name:'bill'}"></child1> <child1 ref="child1" :msg="{name:'bill'}"></child1>
首先冒号是v-bind的缩写,不带冒号后面是字符串,带了冒号就是数据绑定,引号里面的内容是变量或者表达式,
组件内不能修改props的值,同时修改的值也不会同步到组件外层,即调用组件方不知道组件内部当前的状态是什么react
vue 组件props传递时,为何有时候须要加冒号,有时候不须要?
如何在Vue2中实现组件props双向绑定webpack
若是计算属性是对象的话,能够设置他的属性。git
数据可能更新了,可是没有绑定到dom上面的话,不会调用update钩子函数。github
因此在这个时候应该用Object.assign()从新生成新的对象。第一级属性值更新的话,data是更新的!web
style = { color: "rgb(66, 180, 232)" }; //下面渲染不出来 style = { color: "rgb(66, 180, 232)"; };
vue2.0 的时候把过滤器移除了,如今2.10又加了上去,vue-router
定义filter过滤器:
写在实例Vue内部的是局部过滤器,vuex
new Vue({ filters:{ formatMoney: function (value){ return "$"+value.toFixed(2); } } })
写在外部的是全局过滤器segmentfault
Vue.filter("money", function (vaule, type) { return "¥" + vaule.toFixed(2) + type; })
组件内调用:
<span v-text="message | wrap 'before' 'after'"></span>//1.x的写法,2直接wrap('before','after')调用 Vue.filter('wrap', function (value, begin, end) { return begin + value + end })
补充下:一个竖线 | 在js中是二进制运算
注意:在变异(不是替换)对象或数组时,旧值将与新值相同,由于它们的引用指向同一个对象/数组。Vue 不会保留变异以前值的副本。
有时候,你可能想在某个组件的根元素上监听一个原生事件。可使用 .native 修饰 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
若是在同一标签使用,v-if就是用来过滤v-for里面的数据的,先走if的话用template套在外面
今天并列使用的时候遇到的巨坑:
<topic v-for="(topic,idx) in topics" :model="topic" :showIdx="false" :clickHandler="handleTopicClick" v-if="mode==0"/> <school-topic v-for="t in topics" :model="t" :style="showStyle(t)" :clickHandler="handleTopicClick" v-else />
结果topics只有三条数据,可是渲染出9条数据,官网说的很清楚:v-for with v-if
keep-alive
缓存组件在内存中,再次进入该页面不会从新渲染,用于保存页面的原始状态<template> <div id="app"> <keep-alive include="SelectTopics"> <router-view></router-view> </keep-alive> </div> </template>
即便设置了keep-alive
组件的beforeUpdate
和updated
钩子函数仍是会调用的。
activated和unactivated钩子是在keep-alive组件里面被调用的,不是第一次进入keep-alive组件的话,调用顺序是:beforeEach
->beforeRouteEnter
->activated
->beforeUpdate
->beforeRouteEnter
的next
函数
也能够在离开页面的时候手动销毁改组件:
beforeRouteLeave(to, from, next) { if (to.path === "/examcentre") { this.$destroy(); } next(); } //或者 deactivated: function () { console.log(4) this.$destroy(); },
有时候根据需求(好比该组件是复用的)须要在再次进入该页面的时候从新从后台获取数据,那么能够在activated
钩子函数中请求数据来update页面。
vue.js 可否设置某个组件不被keep-alive?
vue2.0 keep-alive最佳实践
Vue如何作到前进刷新数据,后退不刷新数据呢?
<keep-alive>组件缓存问题
Vue路由开启keep-alive时的注意点
vue.js+vue-router+webpack keep-alive用法
因此要想清除vuex state里面的数据的话,能够放在beforeRouteLeave
里面作处理。
this.$store.commit("SET_PAPERATTRIBUTE", {});
mint-ui 中的Toast MessageBox Indicator 调用的方式是Toast('提示信息');
或者在全局引入mint-ui而后再组件里this.$toast("提示信息")
,这种方式和咱们普通的引入组件的方式都不一样,一般咱们是在模板里直接将组件放到模板里面,这就意味着父组件在render的时候,子组件也被render到了dom里面:
<template> <div class="my-set-attr-wrap"> <set-attribute ref="setMyAttr" :style="setAttrStyle" :model="attributeModel" /> </div> </template>
this.$toast("提示信息")
这种是在函数中调用,确定也是要render到dom里面的,改咋办呢?查看了mint-ui的实现方式:document.body.appendChild(instance.$el);
目录:
TopicDetailPopup.vue文件就是普通的vue写法,
index.js:
这里考虑到每次弹出层不能都去建立新的组件,咱们只须要将组件内的数据更新就能够了,dom也不须要删除,而后再建立,就用到了单例模式,这边的instance是在父组件没销毁以前都是存在的,每次只是更新了组件的数据,为啥没被销毁呢,这边造成了一个闭包:
调用:
import TopicDetailPopup from '../topicDetailPopup/index.js' TopicDetailPopup.open({ detail: res.data });
可是这个地方出现个问题this.$store
如今为undefined
,应该是由于这个组件是直接new实例化的,而不是经过根组件嵌套的,
main.js
new Vue({ router: router, store, render: h => h(App) }).$mount("#app");
store注册在根组件里面,而弹窗组件没有和根组件关联,因此拿不到store。
要是能将弹窗组件插入其余组件问题就能解决了,貌似如今API没有提供这样的接口,vue2动态添加组件的话能够用render函数,能够我如今的弹窗组件是模板的形式,也能够动态插入到父组件,<component :is="componentId"></component>
且须要在components里面引用,这样又回到了模板语法了。
弹窗的弊端:
vue-devtools 无法检测到组件,也无法检测到vuex,对于webapp来讲返回键无法使用,关闭不了当前的弹窗,形成上面的问题都是因为没用使用router。
对于安卓手机返回键无法使用能够采用曲线救国的方式,禁用返回键,js无法直接操做安卓返回键,可是可使用beforeRouteLeave
,使得返回键没有效果,
beforeRouteLeave(to, from, next) { if (this.popupVisible) {//弹窗显示的话,路由无法跳转 next(false); } else { next(true); } }
弹窗的好处:
在当前页面直接弹出,这样能够保存当前页面的数据和滚动条的位置,还有就是组件复用的话,直接关闭弹窗,不须要根据不一样的页面去回退或者前进到特定的页面。
v-model一般用于input的双向数据绑定 <input v-model="parentMsg">
,也能够实现子组件到父组件数据的双向数据绑定:
首先说说v-model的用法:
model.vue
<template> <div> 父: <input type="text" v-model="msg"> <child v-model="msg"></child> </div> </template> <script> import child from './modelChild.vue' export default { name: "model", props: { }, components: { child }, data() { return { msg: "ppp" } }, methods: { } } </script> <style lang="less"> </style>
modelChild.vue
<template> <div> 子: <input type="text" @input="handleInput" class="text" :value="value"> </div> </template> <script> export default { name: "modelChild", props: ["value"], methods: { handleInput(e) { this.$emit("input", e.target.value) } } } </script> <style lang="less"> .text { height: 20px; width: 200px; } </style>
不管改变父组件仍是子组件的输入框,value和msg的值都会改变,两个输入框的值也就同时改变了。
:model和v-model的区别
:model是v-bind:model的缩写,<child :model="msg"></child>
这种只是将父组件的数据传递到了子组件,并无实现子组件和父组件数据的双向绑定。固然引用类型除外,子组件改变引用类型的数据的话,父组件也会改变的。
查看vue-router源码的时候发现install.js里面两句:
Vue.component('router-view', View) Vue.component('router-link', Link)
这两句就是全局注册了这两个组件,
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
这三步后,在组件里直接使用 <router-view></router-view>
而不用先import再使用。
在mint-ui里也是相同的作法:
src/index.js
const install = function(Vue) { if (install.installed) return; Vue.component(Header.name, Header);//注册全局组件 Vue.component(Button.name, Button); Vue.use(InfiniteScroll);//使用指令插件 Vue.use(Lazyload, { loading: require('./assets/loading-spin.svg'), try: 3 });//使用指令插件或lazy-component Vue.$messagebox = Vue.prototype.$messagebox = MessageBox; Vue.$toast = Vue.prototype.$toast = Toast; Vue.$indicator = Vue.prototype.$indicator = Indicator; };
后面的Vue.$toast = Vue.prototype.$toast = Toast;
使得咱们能够在组件中直接调用this.$toast("提示信息")
以前在写react的时候是不能够这么作的,今天查看了popup.vue的时候发现vue是能够这么干的,直接渲染到了组件的根元素上面。用在组件上
props: { fixed: Boolean, value: {} }
今天在concat两个数组的时候发现数据更新了,页面并无刷新,debug看了下数据,concat的数据没有get set属性访问器,致使后来push的数据也没有属性访问器。以前没有细看文档。搜了下原来push是变异方法,concat不是。
解决办法有二:
使用变异方法
使用vue component的$set函数
看一些小伙伴的回答是data的$set方法,至少vue2是没有的。具体可查看文档列表渲染
个人解决办法是:
Array.prototype.push.apply(arr, item);
今天在模板.vue文件里加入render函数发现并不会执行render函数,原来是vue-loader
会将template
转成render函数,因此只能二选一。.vue文件如何使用render函数渲染组件
<input type="number">
在pc和手机端均可以实现只能输入数字,但是手机端弹出的软键盘里面没有完成或者搜索按钮,搜了下,如今的HTML5 number的状况下并无支持搜索按钮,type='text'是有的。因此曲线救国,控制表单只能输入数字。
起初的想法是先把在
<input type='text' @input="handleInput" :value="val"/> handleInput(e){ this.val=e.target.value.replace(/[^\d]/g,''); }
可是这种并不会实时刷新表单的数据,下面就会起做用
e.target.value=e.target.value.replace(/[^\d]/g,'');
优雅点的写法,用自定义指令:
//<input type="text" v-number-only /> directives: { numberOnly: { bind: function(el) { el.handler = function() { el.value = el.value.replace(/\D+/, '') } el.addEventListener('input', el.handler) }, unbind: function(el) { el.removeEventListener('input', el.handler) } } },
因为弹出层是单例模式,因此打开弹出层只会执行一次mounted钩子函数,我去监听
visible(val) { if (val) { this.$refs.textbox.focus();//这样并不能使文本框获取焦点 } else { this.detail = null; this.$refs.textbox.value = ""; } }
解决办法也是使用自定义指令
focus: { update(el) { el.focus(); } }
平时在写组件里面的样式加上scoped
,避免样式的全局污染,而从后台返回的HTML无效的,解决办法就是在组件里再加一对style标签,将样式写到这里。