Vue项目经验javascript
setInterval路由跳转继续运行并无及时进行销毁
好比一些弹幕,走马灯文字,这类须要定时调用的,路由跳转以后,由于组件已经销毁了,可是setInterval尚未销毁,还在继续后台调用,控制台会不断报错,若是运算量大的话,没法及时清除,会致使严重的页面卡顿。
解决方案:在组件生命周期beforeDestroy中止setInterval
beforeDestory() {
clearInterval(this.timer);
MessageBox.close()
}php
使用vue过程当中你遇到了什么困难?
多级嵌套传参,解决思路自行百度
路由嵌套
路由嵌套会将其余组件渲染到该组件内,而不是进行整个页面跳转router-view自己就是将组件渲染到该位置,想要进行页面跳转,就要将页面渲染到根组件,在起始配置路由时候写到:
var App = Vue.extend({ root });
router.start(App,'#app');
这里首先将根组件注册进来,用于将路由中配置好的各个页面渲染出来,而后将根组件挂载到与#app匹配的元素上。css
组件的异步加载(按需加载组件)
在平时的demo中,你可能不会碰见这个需求,当页面不少,组件不少的时候,你会发现你的页面在首次加载的时候,异常的慢,这个是由于vue首次加载的时候把可能一开始看不见的组件也一次加载了,这个时候就须要对页面优化了,就须要异步组件了。如何去写异步组件呢,实际上很简单,只须要在你的路由index,js里加上require就能够了,像下面这样,这也是所谓的按需加载组件的实现原理。html
vuejs构建组件使用
Vue.component('componentName',{ /*component*/ });
这里注意一点,组件要先注册再使用,也就是说:
Vue.component('mine',{
template:'#mineTpl',
props:['name','title','city','content']
});前端
var v=new Vue({
el:'#vueInstance',
data:{
name:'zhang',
title:'this is title',
city:'Beijing',
content:'these are some desc about Blog'
}
});
若是反过来会报错,由于反过来表明先使用了组件的,可是组件却没注册。
webpack报错后,使用webpack --display-error-details能够排错vue
如何让css只在当前组件中起做用
在每个vue组件中均可以定义各自的css,js,若是但愿组件内写的css只对当前组件起做用,只须要在style中写入scoped,即:
<style scoped></style>java
vuejs循环插入图片
在写循环的时候,写入以下代码:
<div class="bio-slide" v-for="item in items">
< img src="{{item.image}}">
</div>
此时在控制台会出现警告
[Vue Warn]: src="{{item.image}}": interpolation in "src" attribute will cause a 404 request. Use v-bind:src instead.这里意思是在“src”属性插值将致使404请求。使用v-bind:src代替。
因此替换成以下:
<div class="bio-slide" v-for="item in items">
< img v-bind:src="item.image">
</div>
这里须要主要,v-bind在写的时候不能再用{{}},根据官方的说法:
<a v-bind:href="url"></ a>
这里 href 是参数,它告诉 v-bind 指令将元素的 href 特性跟表达式 url 的值绑定。可能你已注意到能够用特性插值href="{{url}}" 得到一样的结果:这样没错,而且实际上在内部特性插值会转为 v-bind 绑定。node
绑定value到Vue实例的一个动态属性上
对于单选按钮,勾选框及选择框选项,v-model绑定的value一般是静态字符串(对于勾选框是逻辑值):
<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle">
可是有时候想绑定value到vue实例的一个动态属性上,这时能够用v-bind实现,而且这个属性的值能够不是字符串。例如绑定Checkbox的value到vue实例的一个动态属性:
<input
type="checkbox"
v-model="toggle"
v-bind:true-value="a"
v-bind:false-value="b">
<p>{{toggle}}</p >
这里绑定后,并非说就能够点击后由true,false的切换变为a,b的切换,由于这里定义的动态a,b是scope上的a,b,并不能直接显示出来,此时
//当选中时
vm.toggle === vm.a
//当没选中时
vm.toggle === vm.b
因此此时须要在data中定义a,b,即:
new Vue({
el:'...',
data:{
a:'a',
b:'b'
}
});linux
实现多个根据不一样条件显示不一样文字的方法
v-if,v-else能够实现条件选择,可是若是是多个连续的条件选择,则须要用到计算属性computed。例如实现当输入框中什么都没写的时候显示字符串‘empty’,不然显示输入框中的内容,代码以下:
<div id="test">
<input type="text" v-model="inputValue">
<h1>{{changeVaule}}</h1>
</div>
new Vue({
el:'#test',
data:{
changeVaule:'123'
},
computed :{
changeVaule:function(){
if(this.inputValue!==''){
return this.inputValue;
}else{
return 'empty';
}
}
}
});webpack
Vuejs在变化检测问题
1.检测数组
因为javascript的限制,vuejs不能检测到下面数组的变化:
直接索引设置元素,如vm.item[0]={};
修改数据的长度,如vm.item.length。
为了解决问题1,Vuejs扩展了观察数组,为它添加一个$set()方法:
// 与 `example1.items[0] = ...` 相同,可是能触发视图更新
example1.items.$set(0, { childMsg: 'Changed!'})
问题2,须要一个空数组替换items。
除了$set(),vuejs也为观察数组添加了$remove()方法,用于从目标数组中查找并删除元素,在内部调用了splice()。所以,没必要:
var index = this.items.indexOf(item)
if (index !== -1) {
this.items.splice(index, 1)
}
只需:
this.items.$remove(item);
2.检测对象
受ES5的显示,Vuejs不能检测到对象属性的添加或删除。由于Vuejs在初始化时候将属性转化为getter/setter,因此属性必须在data对象才能让Vuejs转换它,才能让它是响应的,例如:
var data = { a: 1 }
var vm = new Vue({
data: data
})
// `vm.a` 和 `data.a` 如今是响应的
vm.b = 2
// `vm.b` 不是响应的
data.b = 2
// `data.b` 不是响应的
不过,有办法在实例建立以后添加属性而且让它是响应的。对于Vue实例,可使用$set(key,value)实例方法:
vm.$set('b', 2)
// `vm.b` 和 `data.b` 如今是响应的
对于普通数据对象,可使用全局方法Vue.set(object, key, value):
Vue.set(data, 'c', 3)
// `vm.c` 和 `data.c` 如今是响应的
有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 添加属性。可是,添加到对象上的新属性不会触发更新。这时能够建立一个新的对象,包含原对象的属性和新的属性:
// 不使用 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
关于vuejs页面闪烁{{message}}
在vuejs指令中有v-cloak,这个指令保持在元素上直到关联实例结束编译。和CSS规则如[v-cloak]{display:none}一块儿用时,这个指令能够隐藏未编译的Mustache标签直到实例准备完毕。用法以下:
[v-cloak]{
display:none;
}
<div v-cloak>{{message}}</div>
这样<div>不会显示,直到编译结束
关于在v-for循环时候v-model的使用
有时候须要循环生成input,用v-model绑定后,利用vuejs操做它,此时咱们能够在v-model中写一个数组selected[$index],这样就能够给不一样的input绑定不一样的v-model,从而分别操做他们。这个我在demo中的dataBind.vue中用到。
vuejs中过渡动画
在vuejs中,css定义动画:
.zoom-transition{
width:60%;
height:auto;
position: absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%);
-webkit-transition: all .3s ease;
transition: all .3s ease;
}
.zoom-enter, .zoom-leave{
width:150px;
height:auto;
position: absolute;
left:20px;
top:20px;
transform: translate(0,0);
}
其中动画在定的时候要注意上下对应,上面有什么,下面有什么,都要变化的,若是有不变化的,应该抽离出去,做为公共css样式,在上面的css中,若是我只写 transform: translate(-50%,-50%);而不写下面的transform: translate(0,0);则会致使上面的transform: translate(-50%,-50%);被添加到下面,认为这个是不变的。
关于vuejs中使用事件名
在vuejs中,咱们常常要绑定一些事件,有时候给DOM元素绑定,有时候给组件绑定。绑定事件在HTML中用v-on:click-"event",这时evet的名字不要出现大写,由于在1.x中不区分大小写,因此若是咱们在HTML写v-on:click="myEvent"而在js中写myEvent就出错误,因此在vuejs的1.x绑定事件时候,要尽可能避免使用大写字母。在2.0中没有该限制!
v-if与v-show的区别
v-if直接不渲染这个DOM元素,而v-show是会渲染DOM元素,只是使用display:none隐藏,打开开发者工具能够看到该DOM
关于transition全局钩子如何在组件中使用
Vue.transition是定义一个全局transition钩子的,若是想针对组件定义,则须要以下写法:
export default{
transition:{
'fade':{
enter() {},
leave() {}
}
}
}
这样fade这个过分钩子只会做用于组件内,若是同时有同名的全局钩子,则会优先使用组建定义的
利用vue-router如何实现组件在渲染出来前执行某个事件
export default{
data(){
return{
selected:0,
currentView:'view_0'
}
},
methods:{
choose(index) {
this.selected=index;
this.currentView='view_'+index;
}
},
route:{
data() {
/*每次切换路由,在渲染出页面前都会执行*/
}
}
}
Vue运行报错-。
[Vue-warn]: Missing required prop: "to" (found in component <router-link>) //报错1
这个错误是<router-link>少了个to或者是写错
解决: 正确写法为:<router-link to="/home">
路由在作字符串拼接的时候,to要做为一个属性绑定 <router-link :to="'/home/'+item.id">
-。 声明click/on-click的方法找不到
报错
[Vue warn]: Invalid handler for event "on-click": got undefined //报错1
解决: click/on-click的方法 没有写到methods:{ }里面。
给组件内的原生控件添加事件,不生效的问题
<!--好比用了第三方框架,或者一些封装的内置组件; 而后想绑定事件-->
<!--// 错误例子01-->
<el-input placeholder="请输入特定消费金额 " @mouseover="test()"></el-input>
<!--// 错误例子02-->
<router-link :to="item.menuUrl" @click="toggleName=''">
<i :class="['fzicon',item.menuIcon]"></i>
<span>{{item.menuName}}</span>
</router-link>
<!--上面的两个例子都无法触发事件!!!-->
<!--究其缘由,少了一个修饰符 .native-->
<router-link :to="item.menuUrl" @click.native="toggleName=''">
<i :class="['fzicon',item.menuIcon]"></i>
<span>{{item.menuName}}</span>
</router-link>
<!--明明官方文档有的,一堆人不肯意去看,,Fuck-->
<!--https://cn.vuejs.org/v2/guide/components.html#给组件绑定原生事件-->1234567891011121314151617181920
-。
在函数内用了this.xxx=,为何抛出 Cannot set property 'xxx' of undefined;
这是this的套路了..this是和当前运行的上下文绑定的…
通常你在axios或者其余 promise , 或者setInterval 这些默认都是指向最外层的全局钩子.
简单点说:”最外层的上下文就是 window,vue内则是 Vue 对象而不是实例!”;
解决:
暂存法: 函数内先缓存 this , let that = this;(let是 es6, es5用 var)
箭头函数: 会强行关联当前运行区域为 this 的上下文;
关于this的知识, 推荐读阅 <<你不知道的 JS 系列>>
兼容问题
使用了 axios, IE 整个家族都不支持 promise,
解决方案:
npm install es6-promise
// 在 main.js 引入便可
require("es6-promise").polyfill(); // ES6的polyfill
终于作完了第一个vue项目,本项目前端采用Vue,后端采用express+mongodb,Vue是使用vue-cli生成的项目。
开发期的问题以下:
(1)最好使用cnpm代替npm安装依赖,由于开发过程当中少部分包若是用npm是没法下载完成,一直卡住,换为cnpm毫无压力记得加上--save选项,不然别人安装的话会缺乏包,linux下记得配置软链接才能使用cnpm命令
(2)express如何设置favicon: 其实默认express已经引入了serve-favicon包,只须要使用app.use(favicon(__dirname+你的favicon路径))便可
(3)百度地图的引入须要异步加载,不然会报错找不到BMap,具体见代码
(4)非父子组件通讯新建一个Vue实例做为通讯中转站,能够很方便的处理大部分非父子通讯逻辑
(5)引入reset.css是在main.js中引入
(6)es6的import规则:若是路径最终是一个文件夹,则会首先观察文件夹下是否有 package.json ,若是有 package.json 则会去加载 main 字段指向的文件,若是没有 package.json ,则会在这个文件夹下寻找 index 文件并加载。因此main.js里面加载router直接这样写 import router from './router'
(7)为了处理某些浏览器兼容,好比ie,safari,必须引入babel-polyfill才行,在main.js里加上import 'babel-polyfill',不然ie和safari会不认识es6的语法
(8)main.js里面Vue实例的template:"<App/>"的意思是将app组件替换掉#app的那个div,同时App也是一个组件,在components里面必需要声明
(9)vuex状态管理器的使用最好按照官网那一套来写,比较规范
(10)前端路由验证登陆状况能够在路由里加上meta参数,以下图,而后router.beforeEach里判断requireAuth是否为真
(11)组件里面data使用图片路径是要用require('./../mm.png')才能正确访问图片,这样才可以被webpack正确解析
(12)下拉框最好不用原生的,不一样浏览器表现不一样,得本身写一套才行
(13)server端express自带前端部分,在views里面,注意设置engine解析,是html的引擎,引入ejs包
app.set('views', path.join(__dirname, 'views'));
app.engine('.html',ejs.__express);
app.set('view engine', 'html');
(14)开发环境下个人项目路径下有中文,结果jieba分词包执行的时候报错:找不到jieba.node,而后将路径改成英文问题解决,得出结论路径别加中文,指不定啥问题会出现
部署服务器出现的问题:
(1)首先express默认设置的是3000端口,因此多个项目部署的话得修改bin/www里面的port值,改成不同的
(2)线上部署首先得把server文件夹内的所用内容拷贝到阿里云服务器上,新建一个文件夹来存放。阿里云服务器必须得设置安全组,目的是将开放访问的端口,不然端口没法访问,好比express设置了4000端口,阿里云这里就得设置4000端口开放
(3)服务器环境搭建:首先安装node,而后安装mongodb,注意服务器上的mongodb必须设置访问权限,不然很是不安全,同时server端链接mongo的语句也得加上用户名和密码
(4)代码拷贝后执行cnpm install 安装依赖,安装完成node www启动项目,此时遇到问题以下图,能够看出此时的node不支持async函数,也就是说node版本过低了,可是我本地测试没问题,查询node版本后发现,本地node是v8.3.0,服务器上是v6.4,所以要升级node,具体方法为:1,安装n模块 npm install -g n,这个模块专门管理node版本的,2,n stable此命令可升级到最新稳定版,n v8.3.0这个命令可升级到指定版本。我将服务器上的node升级到和本地同样后问题解决了
(5)因为本项目使用了selenium-webdriver自动化测试工具当作爬虫(缘由是某些网站主内容在iframe内,通常爬虫没法获取内容,selenium内有switchToFrame方法切换frame从而获取到内容),本地测试时这个工具运行时会自动打开chrome(事先设置了chrome参数),可是放到阿里云服务器上时报错找不到chrome binary,查询后发现必须安装chrome浏览器,具体连接http://www.linuxidc.com/Linux/2016-05/131096.htm 而后继续启动发现仍然报错:chrome failed to start. 仔细分析后发现这是因为没有设置headless参数致使的,因为阿里云服务器没有界面,必须设置启动方式为headless无头,同时记得添加参数no-sandbox,不添加则chrome仍然没法启动,如下代码在官网上在找到的。
(6)前端打包后将dist内的文件拷贝到server里面views目录下便可,而后启动express便可访问页面,可是页面里面出现许多png not found,检查后发现是路径问题,这些找不到的png的路径都是写在css里面,因为打包后路径发生改变,因此找不到。解决方法是修改前端build/util.js 里面的路径,添加publicPath参数
未解决的问题以下:
(1)开发环境下访问第三方网站必须作跨域处理,为啥生产环境下能够不用跨域?直接这样写就行
(2)
vue 项目搭建
前言
基于Vue.js 2.x系列 + Element UI 的组件化开发方案,vue.js不支持IE8及其如下版本,由于 Vue.js 使用了 IE8 不能模拟的 ECMAScript 5 特性。 Vue.js 支持全部兼容 ECMAScript 5 的浏览器。vue的安装依赖于node.js,要确保你的计算机上已安装过node.js。可进入cmd编辑器,输入命令 node -v进行查看。node尽可能要用新一些的版本,不然后续安装会提示node版本太低。去node官网下个新版的node从新安装就能够。
安装步骤
1.全局安装node.js
下载地址:https://nodejs.org/en/download/
安装成功后可进入cmd编辑器,输入命令 node -v进行查看,出现版本号说明安装成功,npm是包管理工具,noed安装好就有npm指令了
C:\Users\user>node -v
v8.4.0
C:\Users\user>
2.全局安装webpack 和 vue-cli
npm install -g webpack
npm install -g vue-cli
3.根据vue-cli构建项目
vue init webpack my-vue //建立一个项目,名称my-vue1
cd my-vue // cd 到my-vue的根目录下1
npm install // 下载项目依赖1
npm run dev // 让该项目在本地上跑起来1
这样一个基础的vue项目目录就自动会展示在你面前,咱们能够来看一下其自动生成的基础文件:
项目结构简单介绍
├── build // 是一些webpack的文件,配置参数什么的,通常不用动
│ ├── build.js
│ ├── check-versions.js
│ ├── dev-client.js
│ ├── dev-server.js
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config // 环境配置文件,是vue项目的基本配置文件
│ ├── dev.env.js
│ ├── index.js
│ └── prod.env.js
├── node_modules // npm包文件 是项目中安装的依赖模块
├── src // 源码文件夹,基本上文件都应该放在这里。
│ ├── assets //资源文件夹,里面放一些静态资源
│ │ └── logo.png
│ ├── components //这里放的都是各个组件文件
│ │ └── Hello.vue
│ ├── router
│ │ └── index.js
│ ├── App.vue //App.vue组件
│ └── main.js //入口文件
├── static //生成好的文件会放在这个目录下。
├── .babelrc // babel配置文件 , vue开发须要babel编译
├── .gitignore // gitignore忽略文件
├── .editorconfig // 编码风格配置文件
├── .postcssrc.js // postcss配置文件
├── package.json // node包管理文件
├── index.html // 首页模板
├── package.json // 包管理文件
└── README.md // 描述文件123456789101112131415161718192021222324252627282930313233
main.js文件介绍
这里是入口文件,能够引入一些插件或静态资源,固然引入以前要先安装了该插件,在package.json文件中有记录。
/*引入Vue框架*/
import Vue from ‘vue’
/*引入资源请求插件*/
import VueResource from ‘vue-resource’
/*重置样式*/
import “assets/css/base.css”
/*基本JS*/
import “assets/js/common.js”
/*引入路由设置*/
import “./routers.js”
/*使用VueResource插件*/
Vue.use(VueResource)
App.vue
这是一个标准的vue组件,包含三个部分,一个是模板,一个是script,一个是样式,这里须要了解vue的基础。
import Hello from './components/Hello'
export default {
name: 'app',
components: {
Hello
}
}
app {
font-family: ‘Avenir’, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
vue-route
做用:
经过管理url实现url和组件的对应,
经过url进行组件之间的切换
必须引入router组件 是单独文件
Hello App!
Go to Foo
Go to Bar
axios使用
## 安装 ##
npm install axios vue-axios -D
在main.js 入口文件里面写
import Axios from ‘axios’
import VueAxios from ‘vue-axios’
Vue.use(VueAxios,Axios)
在其它组件里面调用
Javascript
export default {
name: 'blog',
created () {
this.getGoods()
},
methods: {
getGoods () {
this.$http.get('http://lc.shudong.wang/api_goods.php')
.then((res) => {
console.log(res.data)
})
.catch((error) => {
console.log(error)
})
}
}
}
## vue UI组件
使用目的:
提升开发效率
直接拿过来用
elementUi
安装
npm ielement-ui -D
## 引入 main.js 入口文件 ##
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
Vue.use(ElementUI)
hipv2头痛的问题
一、先操做element分页,切换到第2页
模拟画面数据从新查询,从代码里面将current-page强制设置为1(即从新查询数据,并将当前页重置为第1页)
此时画面显示是对的,分页组件已经将第1页的页码数字激活了
而后点击第2页数字,进行换页
画面显示也是对的,第2页数字变成激活状态,可是此时居然没法触发current-change事件
我的猜想,其内部逻辑也许还认为当前页是第2页,因此没有再次触发current-change
这样会致使数据从新加载后,分页出现bug,没法加载分页数据
解决分页BUG的办法
一、使用v-if强制刷新组件便可组件声明改为:(data里面初始化paginationShow为true)
<el-pagination
v-if="paginationShow"
:current-page.sync ="currentPage"
background @current-change="pageChange"
:page-size="perPage"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
二、把search方法改为下面这样:
search () {
this.paginationShow = false
// 模拟ajax查询数据处理,查询成功后执行下面代码
this.total = res.data.total;
this.perPage = res.data.pageSize;
this.$nextTick(function () {
this.paginationShow = true
})
}
三、注意事项:
paginationShow = true,从新显示分页,必须放到$nextTick,画面刷新完毕后,否则无效果1234567891011121314151617181920212223242526272829
后期项目优化
第一次使用vue2.0开发,在使用vue-cli脚手架打包后(UI用的Element-ui)(请求模块用的时axios),发现vendor文件很大,2M左右。。后来翻阅资料才明白,原来webpack把全部的库都打包到了一块儿,致使文件很大。
个人优化方法:
方法1:
1.把不常改变的库放到index.html中,经过cdn引入,好比下面这样:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- <meta base="/MBSS/"> -->
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="shortcut icon " type="images/x-icon" href="/static/img/bitbug_favicon.ico">
<!-- <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> -->
<title>和佳医院信息集成平台</title>
<!-- 先引入 Vue -->
<!--开发环境-->
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
<!--生产环境-->
<!--<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>-->
<!-- 引入组件库 -->
<script src="https://cdn.bootcss.com/axios/0.15.3/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.3.3/index.js"></script>
<script src="https://cdn.bootcss.com/echarts/4.0.4/echarts-en.common.js"></script>
<script src="./static/js/config.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>12345678910111213141516171819202122232425262728
2.而后找到build/webpack.base.conf.js文件,在 module.exports = { } 中添加如下代码:
externals:{
'vue': 'Vue',
'element-ui': 'ELEMENT',
'echarts':'echarts',
'axios':'axios'
}123456
3.在mian.js中import … from …就能够去掉了,若没去掉webpack仍是会把对应的依赖进行打包。
这样webpack就不会把vue.js, echarts, element-ui, axios库打包了。声明一下,我把main.js中对element的引入删掉了,否则我发现打包后的app.css仍是会把element的css打包进去,删掉后就没了。
而后你打包就会发现vendor文件小了不少~
若是你还不知足,请接着往下看·····
方法2:
vue路由的懒加载(具体做用,官网查看,这里就很少介绍了)。
刚开始咱们使用路由多是下面这样(router.js),这样一开始进入页面就会把全部的路由资源都加载,若是项目大,加载的内容就会不少,等待的时间页就会越长,致使给用户的很差的体验效果。
import login from '../components/login/login.vue'
import Index from '../components/stystemm/index/index.vue'
import home from '../components/stystemm/home/home.vue'
import ImageList from "../components/stystemm/ImageList/ImageList.vue"
export default new Router({
routes:[
{
path:'/',
component: hospital
},
{path:'',component:home},
{path:'/imageList',component:ImageList}
}
]
})12345678910111213141516
为了把路由分模块,而后每次进入一个新页面才加载该页面所须要的资源(也就是异步加载路由),咱们能够像下面这样使用(router.js):
1.vue异步组件写法:
export default new Router({
routes: [{
path: '/',
name: 'Login',
component: resolve => require(['../components/page/Login.vue'],resolve) ,
},
{
path: '/empi',
name: 'eMPI管理',
component: resolve => require(['../components/common/index.vue'],resolve),
children: [{
path: '/empi/summary',
name: '索引总览',
component: resolve => require(['../components/page/eMPI/pandect/pandect.vue'],resolve)// empi - 总览
},
{
path: '/empi/patient',
name: '患者信息',
component: resolve => require(['../components/page/eMPI/PatientInformation/PatientInformation.vue'],resolve)
}
]
},
{
path: '/role',
name: '404',
component:resolve => require(['../components/page/404.vue'],resolve)
}
]
});
123456789101112131415161718192021222324252627282930
2.es提案的import()写法:
// 下面2行代码,没有指定webpackChunkName,每一个组件打包成一个js文件。
/* const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about') */
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
{
path: '/about',
component: About
}, {
path: '/index',
component: Index
}, {
path: '/home',
component: Home
}12345678910111213141516171819
3.webpack提供的require.ensure() vue-router配置路由,使用webpack的require.ensure技术,也能够实现按需加载。这种状况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
{
path: '/home',
name: 'home',
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
path: '/index',
name: 'Index',
component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
path: '/about',
name: 'about',
component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}12345678910111213
方法3:
在项目config/index.js中能够开启gzip压缩,对打包优化也有很大的帮助
1.首先安装插件 compression-webpack-plugin
cnpm install --save-dev compression-webpack-plugin1
2.设置productionGzip: true
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: true,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report123456789101112
3.npm run build执行后会发现每一个js和css文件会压缩一个gz后缀的文件夹,浏览器若是支持g-zip 会自动查找有没有gz文件 找到了就加载gz而后本地解压 执行。
---------------------
首页头部栏的搜索功能,全局搜索。
直接跳转查询界面,而后这个很简单,输入框回车事件push到查询界面,而后将值一起带过去,初始化查询界面。
但是问题来了,如今查询这个组件里继续输入而后回车。这时候路由是没变化的,组件里的钩子也不会再次执行。怎么监测到搜索内容变化呢。
首先想到的是监测路由数据变化,后来发现太low,
再次想到的是监测vuex数据,搞了半天仍是不行。
最后使用了非父子组件传值,
创建一个bus文件,文件建一个bus.js
内容就是引入vue,创建一个空的vue实例。
在头部搜索栏的组件里引入bus,用bus.$emit()触发一个事件传值,也就是搜索框的回车时触发。在查询界面引入bus,以后bus.$on()获得数据变化。而后作出相应的操做。
这里要注意必定不能使用bus.$(‘value',function(val){});由于这样的话,你的函数里的this会指向空实例bus。因此咱们必须使用es6的写法,val => {};这样的话this会指向当前查询界面的实例。
vue打印功能,window.open(url}这个东西不少bug。第一用户体验,用户必须容许不然就没法弹出,第二响应时间超过必定时间则没法弹出。
解决方法:
跳转一个指定界面,而后重定向。
var newWindow= window.open('')
setTimout(()=>{
newWindow.location.href = '新的url'
},3000);
软删除数据如何过滤
咱们的网站删除若是是后台数据库已有数据是不能硬删除的,只能修改某个字段而后标记为删除,叫作软删除。
这样的话咱们的前端界面渲染时就须要过滤掉你刚刚删除的数据
个人项目里是用的table而后给了tableData | filterData
filterData:
var newData = [];
for(let key of tableData){
if(key.removed !== 1){ newData.push(key) }
return newData
}
简单解释:就是全局过滤器获取原数据,而后若是某个字段是已经删除了,也就是软删除改变了字段的数据,就无论他了,其余的就生成一个新数组而后返回。
共用界面如何刷新
项目里一个费用申报单界面是共用的,不少地方过来查看和编辑也是这个路由这个组件,只是不少input的内容是空或者是不能编辑只能看。
问题来了,你来到这个界面后查看完了忽然想我想如今编辑一个申报单,但是此时此刻你点击路由这个组件是不会更新的,由于vue以为你已经在这个界面了,他是不会理你的。
使用过几个路由钩子,什么routerberfor……,什么放在app.vue里,都只能检测到路由离开进来的变化,而没法就在当前路由点击当前路由的辩护。
解决方法使用watch 监测路由
//监视路由变化,而后初始化界面。
watch: {
'$route' (to, from) {
alert('路由改变了');
}
}
路由配置:
path:urlal
无论是插件仍是你本身写的头部菜单,都必定有一个事件监听到你点击当前路由。在这个事件里咱们来处理
let val = new Date();
this.$router.push({
path: url/val
})
这样你就能够在你的组件里监听到路由变化了。而后也就能够作出相应的操做。原理就是利用参数的变化呗,时间new出来的永远都是不同的。
表单重置
项目中不少时候界面的数据不须要清除,可是一些操做会触发验证事件,而后一串红字你不达到条件就不会消失,这时候很难受,因此就有了重置表单的验证。
关于表单重置,我使用的是element-ui自带的resetFields()事件。
咱们惟一要注意的是,不能再created()钩子中使用,由于this.$refs[formname]中的ref,必定要加载完后才能找到的。不然会报错说你resetFields()事件未定义。因此必定要在mounted()钩子中使用。
require('!style-loader!css-loader!less-loader!./assets/css/common_m.less')
PS:在webpack中配置好了loader以后,不须要在引入文件时写loader和文件后缀。
cssloader:
{
test: /\.css$/,
exclude: /node_modules/,
loader: "style-loader!css-loader",
},
{
test: /\.less$/,
exclud: /node_module/,
loader: "style-loader!css-loader!less-loader",
},
// <router-view></router-view>与写的位置无关
path.join(__dirname,'..');
this.$set(this, '属性', '值')
css scoped 仅本组件
对象能够存图片。使用require便可。
images: {
error: require('./toast-error.png'),
success: require('./toast-success.png'),
load: require('./toast-load.gif'),
waiting: require('./toast-hourglass.svg')
}
border。各屏幕分辨率不一样出现的粗细问题。
公共部分。写成组件。利用传参改变样式/内容。
Ajax。axios。
跨域问题的解决:1.服务器端协助配置。2.jsonp。3.devServer配置代理。
能用data数据解决的问题,不用方法解决。如取反。长度。是否空/false/true。(Vue是数据驱动而不是结构驱动)
v-bind:style src to ...
路由传参。$route。
历史记录切换。router-link to/:to或者router.push()/router.replace()
#router.push(location) 导航到不一样的 URL
// 声明式
<router-link :to="...">
// 编程式
router.push(...)
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
#router.replace(location) 它不会向 history 添加新记录,而是替换掉当前的 history 记录。
// 声明式
<router-link :to="..." replace>
// 编程式
router.replace(...)
#router.go(n) 在 history 记录中向前或者后退多少步,相似 window.history.go(n) 值能够正能够负
#综合使用
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
router.push({ name: 'user', params: { userId: 123 }})
这两种方式都会把路由导航到 /user/123 路径。
// 命名视图
// https://router.vuejs.org/zh-cn/essentials/named-views.html
// https://jsfiddle.net/posva/6du90epg/
// 有时候想同时(同级)展现多个视图,而不是嵌套展现,例如建立一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。
// 你能够在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。若是 router-view 没有设置名字,那么默认为 default。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
// 一个视图使用一个组件渲染,所以对于同个路由,多个视图就须要多个组件。确保正确使用 components 配置(带上 s):
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
重定向 和 别名
切换时清空历史记录。数据丢失。sessionStorage。
相对路径。
append。concat。
渲染成某个标签。tag
能够在router-link内嵌套其余内容。
类型都是Object
$route.params(一个 key/value 对象,包含了 动态片断 和 全匹配片断,若是没有路由参数,就是一个空对象。)
$route.query(一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,若是没有查询参数,则是个空对象。)
<div>
<router-link :to="{ name: 'Hello' , params: { userId: 123 }}">
click1
</router-link>
</div>
<div>
<router-link :to="{ path: 'hello' , query: {show: 2}}">
click2
</router-link>
</div>
console.log(this.$route.params.userId)
console.log('top is params, bottom is query')
console.log(this.$route.query.show)
watch:
watch: {
'$route' (to, from) {
// 对路由变化做出响应...
}
}
v-show和v-if 。v-if为假直接不渲染。v-show为假display none。
当 v-if 与 v-for 一块儿使用时,v-for 具备比 v-if 更高的优先级。
我的建议:外容器overflow hidden,内容器overflow scroll。
过渡效果:
<transition name="fade"></transition>
.fade-enter-active, .fade-leave-active {
-webkit-transition: opacity .7s;
transition: opacity .7s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
路由钩子:判断从哪一个路由过来,到哪一个路由。而后跳转到哪一个路由。(全局钩子。局部钩子。)
component页面内也能够监听路由。
滚动行为。历史记录之间切换。页面位置。返回对象。
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
锚点的实现。经过scrollTop。或滚动行为。
路由元信息。路由嵌套。
懒加载。
在异步加载页面中载嵌入异步加载的组件时对页面是否会有渲染延时影响?
答:会, 异步加载的组件将会比页面中其余元素滞后出现, 页面会有瞬间闪跳影响;
解决方案:由于在首次加载组件的时候会有加载时间, 出现页面滞后, 因此须要合理的进行页面结构设计, 避免首次出现跳闪现象;
At all:
一、路由页面以及路由页面中的组件全都使用懒加载
优势:(1)最大化的实现随用随载
(2)团队开发不会由于沟通问题形成资源的重复浪费
缺点:(1)当一个页面中嵌套多个组件时将发送屡次的http请求,可能会形成网页显示过慢且渲染良莠不齐的问题
二、路由页面使用懒加载, 而路由页面中的组件按需进行懒加载, 即若是组件不大且使用不太频繁, 直接在路由页面中导入组件, 若是组件使用较为频繁使用懒加载
优势:(1)可以减小页面中的http请求,页面显示效果好
缺点:(2)须要团队事先交流, 在框架中分别创建懒加载组件与非懒加载组件文件夹
三、路由页面使用懒加载,在不特别影响首页显示延迟的状况下,根页面合理导入复用组件,再结合方案2
优势:(1)合理解决首页延迟显示问题
(2)可以最大化的减小http请求, 且作其余他路由界面的显示效果最佳
缺点:(1)仍是须要团队交流,创建合理区分各类加载方式的组件文件夹
export default new Router({
routes: [
{
path: '/',
component: resolve => require(['components/Hello.vue'], resolve)
},
{
path: '/about',
component: resolve => require(['components/About.vue'], resolve)
}
]
})
// solve:
// components/page
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 类似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出如今父组件链中。
当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
主要用于保留组件状态或避免从新渲染。
组件:
当注册组件(或者 props)时,可使用 kebab-case ,camelCase ,或 TitleCase 。Vue 不关心这个。
component命名要求:
1. 检查名称是否与 HTML 元素或者 Vue 保留标签重名,不区分大小写。(经常使用HTML标签)
2. 检查组件名称是否以字母开头,后面跟字母、数值或下划线。
使用 Virtual DOM 解析模板时,不会将模板中的标签名转成小写,而是保留原始标签名。而后,使用原始的标签名进行匹配组件。
例如, <MyComponent></MyComponent> 不会转为为小写形式,直接以 MyComponent 为基础开始匹配。
固然,匹配的规则依次匹配:原标签名、camelCase化的标签名、PascalCase化的标签名。
computed,内容变时会更新,不然会缓存起来。
若是是传参等方式获得值,须要判断值是否为空,不然会报值为undefined的错。
vue项目中,不用写CSS的兼容性代码。
由于vue-loader在编译.vue文件的时候,使用了Postcss的工具,它会给有兼容性问题的属性添加兼容性代码。
它是根据can i use官网写的代码。
写在<style></style>内才会生效。在html中添加style属性是不会添加兼容性代码的。
换行问题:
v-html能够直接加<br>进行换行,v-model中无效
例外:textarea标签使用v-model时,可使用\r进行换行
ref的使用:
在父页面调用子组件的标签:
在父页面中的组件上加ref。而后在子组件中的某个标签加ref。便可。
nextTick
将回调延迟到下次 DOM 更新循环以后执行。
https://cn.vuejs.org/v2/api/#vm-nextTick
new Vue({
// ...
methods: {
// ...
example: function () {
// 修改数据
this.message = 'changed'
// DOM 尚未更新
this.$nextTick(function () {
// DOM 如今更新了
// `this` 绑定到当前实例
this.doSomethingElse()
})
}
}
})
box-sizing: border-box
:disabled="type == '值'"
:class = name
name能够是compute
getBoundingClientRect用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。
点击事件。取消冒泡。
v-on:click.stop="doThis"
阻止默认事件。
v-on:click.prevent="doThis"
https://cn.vuejs.org/v2/guide/events.html#事件修饰符
组件内部的方法,命名建议以两个下划线开头
外部传参方法等,不用两个下划线开头。
padding取%值,
> %,规定基于父元素的宽度的百分比的内边距。
给按钮加padding。方便点击
或者整个部分能够点击。
export 和 export default
http://es6.ruanyifeng.com/#docs/module#export-命令
http://es6.ruanyifeng.com/#docs/module#export-default-命令
切换组件时,但愿保留组件的状态时,加上keep-alive 便可
我的作vue项目的心得和体会
vue.js
首先,vue.js是一个数据驱动视图的一个js框架,操做数据,而后实时反应到dom元素上的一个动态视图框架,它也是一个渐进式开发框架,好比,我用vue-cli搭建了一个本地开发环境,用nodejs跑了起来,当把vue引进来以后,要作项目仍是远远不够的,就用到了vue全家桶
好比
UI框架 : element-ui
http请求工具:axios(我的推荐用这个)
cookie工具:vue-cookie
构建工具:vue-cli
路由插件:vue-router
状态管理工具:vuex
滚动条插件:vuescroll
兼容IE的插件:babel-polyfill(固然vue只兼容到IE9+)
若是平时项目中你用到了哪些框架及插件,就能够经过npm install,下载下来,引入到项目中去就ok了
我的以为项目目录结构能够是这个样子的
主要是src文件夹,assets主要用于放一些项目中的图片等之类的,compoents就放一些本身定义的组件,pages就放页面,固然都是vue文件啦,router放路由配置,server放一些静态目录什么的,放一些常量什么的均可以,store,熟悉vuex的小伙伴应该都知道,没错,就是放vuex的
经过用vue作了一些东西后,引起了个人一些思考,也算是心得吧,跟我写代码的风格有关系,也许你以为我说的这些很差,你能够继续延用你的风格,哈哈,毕竟敲代码都有本身独特的风格嘛,哪一个程序猿尚未点傲娇的小脾气呢!
关于使用UI框架
通常我都是用element-ui这个ui框架,其中有一些ui组件特别好用,好比$message,提示组件,不用本身写,直接调用,就能用于增长,修改的一些功能,好比提示新增成功,修改为功等,还有按钮组件,弹出框组件等一些基本的组件,对于我本身写的其余代码后续几乎没有冲突,且灵活度高的,我就直接用了框架内的组件,可是一些可控性不强,且不够灵活,几乎不能改动的组件我就会选择本身写,好比树形控件,这个树形控件的样式特别单一,并且不可控,并且灵活度不高,我不是很喜欢,就利用vue的递归组件本身写树形控件,感兴趣的小伙伴能够看下我下篇博客,立刻就发《vue如何用递归组件写树形控件》,总结一句话,灵活度高,就用框架,灵活度不高,就本身写,本身写的可控性很强!
关于封装组件
有时候项目中常常会碰到这种状况,好几个页面的列表页除了表头不同,几乎样式是如出一辙的,这样的你就能够封装一个列表组件了,可是只适用于样式差很少的列表,若是你以为都封装进一个组件里面,对后续开发的一些可控性不是很强,并且每一个页面的需求都不同,处理方式和方法都不很同样,那么我劝你仍是老老实实本身写列表吧,由于你封装到一个组件中,对于每一个页面的处理方式都要进行判断,这样会显得这个组件很臃肿,我以为还不如分开写,因此是否要把一个功能模块封装进组件,灵活把握就能够了
关于一些目录和http请求
关于一些目录,好比导航目录,通常是写死的,固然也有从后台获取的,我如今这个项目就是从后台获取目录,还有请求URL,和一些http请求,你就能够新建一个server目录,而后分模块的写道js文件夹里面,return出去,而后再在其余页面中引入,这样作的好处是,模块化管理,将常量和http请求进行统一管理,好比下图
我就把http请求进行了统一管理,而后暴露出去,未来有改动我就能够直接改这里就能够了
关于vuex
下面说一说vuex,也许有许多小伙伴对于这个都不知道干吗用的,根据个人理解,vuex并非那么神秘,就是一个公共状态库,是互不联系的两个组件的通讯桥梁,好比我又一个列表组件1,又有一个列表组件2。这两个组件彻底不同,丝毫没有联系的那种,可是它们之间须要通讯,好比都须要根据一个布尔值show来进行显示仍是隐藏,这样就能够把这个show放进vuex状态库里面,当这个show改变的时候,这两个列表组件就能够根据show的变化自动的进行显示隐藏了
关于http请求写在哪里的问题
我一开始接触vuex的时候,vuex里面有一个actions,既能够进行同步操做,又能够进行异步操做,官网上是推荐将http异步请求放在actions里面,由于当时刚学,没有判断能力,就按照官网上来写,在vue文件里面只写逻辑代码,而把全部的http异步请求所有写在了actions里面,这样问题就来了,首先mutations里面的函数必需要用它来提交,并且vue里面经过引入import { mapGetters , mapActions} from 'vuex',来获取到函数和状态,我发现写一个http须要写好多代码,我若是直接写道methods里面,就特别简单,后来我就在想到底放哪里简单些,综合了网上的一些见解,我以为这跟我的代码风格有关系,官网是推荐写到actions里面,但是若是一个页面里面的一些http请求只是本身用,也不跟其余页面以及组件进行通讯的话,我以为没有必要写到vuex里面,写在methods里面反而简单些,反正到最后项目的数据都能流通就能够了,我以为一些http请求获得的数据要和其余组件或页面共用的话,我以为必需要放在vuex里面,这是最棒的办法,若是是本身在本身的小窝里小打小闹,也不影响别人,那么咱们仍是写在methods里面吧,毕竟别人又不用,为何要把它驱逐家门呢,哈哈!!
就说到这里吧
Vue项目经验
动态添加class或style
有时候但愿根据某个状态值来决定是否添加某个类,能够这样:
// 数组语法
<div :class="['a',value==true?'b':'']"> //类a老是存在,当value为真时类b存在
// 对象语法
<div :class="{'a':true,'b':value}"> //类a,b都由value控制
<div :style="{background:'url('+value.url+')'}"> //对于style,最好用对象语法,属性值取自当前vue实例
<div className={style.root} style={{ background: `url(${graduateCelebrate}) center center/ 100% 100% no-repeat content-box` }}>
绑定事件函数
有两种方式:
// 方式1
<div @click='handle'></div> //handle函数的this指向当前vue实例,而且会将event对象传入handle做第一个参数,一般可用event.target获取被点击的DOM元素
// 方式2
<div @click='handle("param1",$event)'></div> //handle函数的this指向当前实例,也可将$event传入handle,做用同上,通常用来获取被点击的DOM元素
关于箭头函数
vue的一些配置项,如mounted,beforeRouteEnter,beforeRouteLeave等,自己是一个函数,若使用箭头函数语法,则其内的this对象不是当前vue实例。所以这三个配置项不要用箭头函数,其它的配置项,如methods,computed,watch等接受对象做为配置的,其内的函数最好用箭头函数,另外setTimeout(fn,time)中的fn最好也用箭头函数。
watch对象变化:
'messages': { // messages是一个数组,监听数组或对象的变化
handler: function(newValue, old) {
if (newValue.length == 0) {
setTimeout(() => {
history.back();
}, 1000)
}
},
deep: true
}
关于beforeRouteEnter和beforeRouteLeave
beforeRouteEnter(to,from,next) 没法访问当前vue实例,通常用于从localStorage中读取数据恢复页面,好比从页面a到b,在从b回到a,若a有数据变化(ajax拉取)就更新页面,不然不更新;或者还原当前滚动条位置
beforeRouteLeave(to,from,next) 可访问当前vue实例,通常用于页面离开时将某些状态保存在localStorage中,例如当前滚动条位置
两者都必须显示调用next函数
keep-alive和router-view混合使用
// 这是目前用的比较多的方式
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
...
routes: [
{ path: '/', redirect: '/index', component: Index, meta: { keepAlive: true }},
{
path: '/common',
component: TestParent,
children: [
{ path: '/test2', component: Test2, meta: { keepAlive: true } }
]
}
....
// 表示index和test2都使用keep-alive
如有三个页面A->B->C,但愿A->B时B拉新数据;C返回B时B不拉新数据,且保存B到C以前的位置,该如何作?
一、给B设置keepAlive:true;
二、在B的beforeRouteEnter中作获取数据的操做,该钩子的三个参数能够判断B的上一个页面,从而决定是否拉数据;
在B的beforeRouteLeave里用localStorage记录位置,并清除和页面展示相关的数据状态;
三、在接口回调里最好用EventCenter这种观察者模式来触发数据获取成功的事件
四、在B的mounted钩子里接受数据获取成功的事件,就能够拿到数据
五、在B的activated钩子里取localStorage里的位置
router-link经常使用方式
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
//对应js
this.$route.params.userId
this.$route.query.plan
过分动画
单元素过渡
transition包一个含有v-if或v-show指令的元素就行
动画过程
多元素过渡
transition下只能有一个根元素,因此多元素时必须用v-if,v-else来保证只有一个,此外,多个相同标签时,最好给每一个标签设置key
多组件过渡
用动态组件便可
列表过渡
需用transition-group组件包裹,被包裹元素必须设置key,其余和单元素同样
数据拉取
数据获取操做最先能够放在每一个组件的beforeRouteEnter里,而后利用观察者模式把数据传到beforeMount钩子函数里作逻辑操做
beforeRouteEnter(to, from, next) {
let feed_id = to.params.id;
if (from.name != 'CommentDetail' && feed_id) {
getArticleDetail({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderArticle', res));
getComment({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderComment', res));
}
next();
}
beforeMount(){
// 一、渲染文章详情
EventCenter.$on('renderArticle', res => {
});
// 二、渲染文章评论
EventCenter.$on('renderComment', res => {
})
}
插件 or 组件
对于全局使用频率较高的最好写成插件,而不是组件。例如loading,toast之类,若写成组件,则须要在每一个父组件中引入该组件,比较麻烦,写成插件就能够直接调用
import $ from 'n-zepto';
import Vue from 'vue';
export default {
install() {
var timer = null;
Vue.prototype.$alerTip = function(text, delay, options) {
var defaultCssObject = {
position: 'fixed',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 10000,
minWidth: '1.5rem',
margin: '0 auto',
left: 'calc((100% - 1.5rem) / 2)',
bottom: '1.4rem',
borderRadius: '.1rem',
height: '.5rem',
lineHeight: '.5rem',
background: '#000',
opacity: 0.85,
color: 'white',
};
var cssObject = options || defaultCssObject;
var temp = `<div class="v-toast">${text}</div>`;
var $div = $(temp);
$div.css(cssObject);
$('body').append($div);
clearTimeout(timer);
timer = setTimeout(() => {
$('.v-toast').remove();
timer = null;
}, delay);
}
}
}
vue父子组件生命周期执行顺序问题
父子组件钩子执行顺序:
father created
father before mounted
son created
son before mount
son mounted
father mounted
因此,你在父组件 beforeMounted 中已初始化的值必定能够经过props下发到子组件
vue-router切换页面滚动条位置问题
注意:scrollBehavior只有在history.pushState可用时才有效,而该方法仅兼容到IE10(移动端可放心使用)
const router = new VueRouter({
routes,
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) { // 经过meta属性精细控制
from.meta.savedPosition = document.body.scrollTop;
}
return { x: 0, y: to.meta.savedPosition || 0 }
}
}
})
vue库的引入问题
vue提供众多版本库文件,在使用*.vue单文件组件的开发模式时,只需引入vue.runtime.min.js便可,该库体积最小,不过要注意初始化vue实例时,不能用template选项,而应该换为render
new Vue({
el: '#app',
router,
render: h => h(App)
})
// webpack对应修改:
alias: {
'vue$': 'vue/dist/vue.runtime.min.js'
}
vuex组件中访问state报错TypeError: Cannot read property ‘state’ of undefined”在组件中使用this.$store.state.test访问state的属性报错,是由于store的实例并未注入到全部的子组件,需修改main.jsnew Vue({el: '#app',store, //将store注入到子组件router,components: { App },template: '<App/>'})