渐进式 JavaScript 框架

Vue.js Vue简介

一个mvvm框架(库)、和angular类似 比较容易上手、小巧 Vue和Angular区别

vue——简单、易学 指令:v-xxx 一片html代码配合上json,在new出来vue实例 适合: 移动端项目,小巧 angular——上手难 指令:ng-xxx 所有属性和方法都挂到$scope身上 适合: pc端项目 共同点: 不兼容低版本IE Vue基本雏形

angular var app=angular.module('app',[]); app.controller('xxx',function($scope){ //C $scope.msg='welcome angular' }) html: <div ng-controller="xxx">{{msg}}</div> vue let vm=new Vue({ el:'#box', //选择器 id className tagName data:{ msg:'welcome vue' } }); html: <div id="box">{{msg}}</div> 常用指令

v-model 双向数据绑定(一般用于表单元素) v-for 循环 :key='index'提高循环性能 **Vue2.0写法**: v-for="(value,index) in arr" v-for="(value,key,index) in json" v-show 显示隐藏 v-on:click/dblclick/mouseover/mouseout... 简写: v-on: => @ 事件

事件对象 @click="show($event)" 事件冒泡 阻止冒泡 a). ev.cancelBubble=true; b). @click.stop 推荐 默认行为(默认事件) 阻止默认行为 a). ev.preventDefault(); b). @contextmenu.prevent 推荐 键盘 @keydown $event 事件源 ev.keyCode 键值 @keyup 常用键 回车 a). @keyup.13 b). @keyup.enter 上、下、左、右 @keyup/keydown.up @keyup/keydown.down @keyup/keydown.left @keyup/keydown.right 属性

v-bind:src="" 简写: :src="" 推荐 <img src="{{url}}" alt=""> 效果能出来,会报错 <img v-bind:src="url" alt=""> 效果可以出来,不会报错 class和style

:class="" v-bind:class="" 1) :class="[red]" red是数据 data:{ red:red 后一个是class名 } :class="[red,blue]" 可传入多个数据 2) :class="{red:true,blue:true}" class名 3) :class="{red:a, blue:b}" 布尔值控制 data:{ a:true, b:false } 4) :class="json" 直接传入一个json data:{ json:{ red:true, blue:false } } :style="" v-bind:style="" 注意: 复合样式,采用驼峰命名法 1) :style="{color:'red'} :style="[c]" data:{ c:{color:'red'} } 2) :style="[c,d]" data:{ c:{color:'red'}, b:{backgroundColor:'blue'} } 3) :style="json" data:{ json:{ color:'red', backgroundColor:'gray' } } 模板

{{msg}} 数据更新模板变化 {{*msg}} 数据只绑定一次 {{{msg}}} HTML转义输出(可识别html标签) **注意{{{ }}}在Vue2.0被废弃** 过滤器(过滤模板数据)

系统提供一些过滤器: {{msg| filterA}} {{msg| filterA | filterB}} uppercase {{'welcome'| uppercase}} 转大写 lowercase {{'WELCOME'| uppercase}} 转小写 capitalize 首位转大写 {{'welcome'|capitalize}} {{'WELCOME'|lowercase|capitalize}} currency 货币 {{msg| currency '参数'}} 数据交互

引入: vue-resouce get: 获取一个普通文本数据: this.$http.get('arr.txt').then(res=>{ alert(res.data); },err=>{ alert(err.status); }); 给服务发送数据: this.$http.get('get.php',{ a:1, b:2 }).then(res=>{ alert(res.data); },err=>{ alert(err.status); }); post: this.$http.post('post.php',{ a:1, b:20 },{ emulateJSON:true }).then(res=>{ alert(res.data); },err=>{ alert(err.status); }); 或者直接写:Vue.http.options.emulateJSON = true; jsonp: this.$http.jsonp('https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',{ wd:'a' },{ jsonp:'cb' //callback名字,默认名字就是"callback" }).then(res=>{ alert(res.data.s); },err=>{ alert(err.status); }); vue生命周期

created -> 实例已经创建 beforeCompile -> 编译之前 compiled -> 编译之后 ready -> 插入到文档中 beforeDestroy -> 销毁之前 destroyed -> 销毁之后 v-cloak

v-cloak 防止闪烁 <span>{{msg}}</span> -> v-text {{{msg}}} -> v-html **注意{{{ }}}在Vue2.0被废弃** 计算属性的使用

computed:{ b(){ //默认调用get return 值 } } computed:{ b:{ get(){return 值} set(val){...} => 参数val就是设置的值的形参 } } * computed里面可以放置一些业务逻辑代码,一定记得return vue实例简单方法

vm.$el -> 就是元素 vm.$data -> 就是data vm.$mount -> 手动挂在vue程序 vm.$options -> 获取自定义属性 vm.$destroy -> 销毁对象 vm.$log() -> 查看现在数据的状态 循环

v-for="(value,index) in data" 出现重复数据: track-by='$index' 提高循环性能 **track-by='$index'在Vue2.0被废弃** 过滤器

vue提供过滤器 capitalize uppercase currency... debounce 配合事件,延迟执行 "fn|debounce 2000" 延迟2s执行函数 数据配合使用过滤器 limitBy 限制几个 =>limitBy 2 =>取数组前两个 limitBy 取几个 从哪开始 =>limitBy 2 0 =>从第0个开始取2个(第二个参数为数字下标) filterBy 过滤数据 =>filterBy 可以是某个变量或者确定字符 orderBy 排序 1 -> 正序 -1 -> 倒序 自定义过滤器

model ->过滤 -> view Vue.filter(name,function(input){ return 代码... }); 自定义指令

Vue.directive('指令名称',function(参数){ this.el -> 原生DOM元素 }); <div v-red="参数"></div> 指令名称: v-red -> red * 注意: 必须以 v-开头 自定义键盘信息

获取键值 document.onkeydown=function(ev){ console.log(ev.keyCode); } Vue自身支持enter以及方向键和字母(a,b,c...)这样的写法 也支持键值的写法,自定义就是给某个键值定义一个名字 自定义键盘信息(Vue1.0) Vue.directive('on').keyCodes.ctrl=17; @keyup.ctrl => 自定义的ctrl就可以使用了 监听数据变化

vm.$watch(name,callback); //浅度监视 vm.$watch(name,callback,{deep:true}); //深度监视 被监听的数据:{ handler:function(val,oldVal){ }, deep:true } bower

(前端)包管理器 npm install bower -g 验证: bower --version bower install 插件名字 bower uninstall 插件名字 bower info 插件名字 =>查看版本信息 vue过渡(动画)

本质走的css3: transtion,animation

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> <script src="bower_components/vue/dist/vue.js"></script> <style> #div1{ width:100px; height:100px; background: red; } //动画 .fade-transition{ transition: 1s all ease; } //进入 .fade-enter{ opacity: 0; } //离开 .fade-leave{ opacity: 0; transform: translateX(200px); } </style> </head> <body> <div id="box"> <input type="button" value="按钮" @click="toggle"> <div id="div1" v-show="bSign" transition="fade"></div> </div> <script> new Vue({ el:'#box', data:{ bSign:true }, methods:{ /*toggle:function(){ alert(1); }*/ toggle(){ this.bSign=!this.bSign; } } }); </script> </body> </html> vue组件

组件: 一个大对象 定义一个组件

1.全局组件 var Aaa=Vue.extend({ template:'<h3>我是标题</h3>' }); Vue.component('aaa',Aaa); *组件里面放数据: data必须是函数的形式,函数必须返回一个对象(json) data(){ return{ } } 2.局部组件(放到某个组件内部) var Aaa=Vue.extend({ template:'<h3>我是标题</h3>' }); var vm=new Vue({ el:'#box', components:{ //局部组件 aaa:Aaa } }); 另一种编写方式: var vm=new Vue({ el:'#box', components:{ 'my-aaa':{ template:'<h2>标题</h2>' } } }); 3.配合模板 a). 单独放到某个地方 <script type="text/v-template" id="aaa"> <h2>标题</h2> </script> var vm=new Vue({ el:'#box', components:{ 'my-aaa':{ template:'#aaa' } } }); b). 直接写在HTML里 <template id="aaa"> <h1>标题</h1> </template> var vm=new Vue({ el:'#box', components:{ 'my-aaa':{ template:'#aaa' } } 4.动态组件 <component :is="组件名称"></component> 和切换选项卡类似 <div id="box"> <input type="button" @click="a='aaa'" value="aaa组件"> <input type="button" @click="a='bbb'" value="bbb组件"> <component :is="a"></component> </div> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ template:'<h2>我是aaa组件</h2>' }, 'bbb':{ template:'<h2>我是bbb组件</h2>' } } }); </script> 组件数据传递

1. 子组件就想获取父组件data 调用子组件: <bbb :m="数据"></bbb> 子组件之内: props:['m','myMsg'] props:{ 'm':String, 'myMsg':Number } 2. 父级获取子级数据 *子组件把自己的数据,发送到父级 vm.$emit(事件名,数据); vm.$dispatch(事件名,数据) 子级向父级发送数据 **在Vue2.0被废弃** vm.$broadcast(事件名,数据) 父级向子级广播数据 **在Vue2.0被废弃** 配合: event:{} slot

位置、槽口 作用: 占个位置 <div id="box"> <aaa> <ul slot="ul-slot"> <li>1111</li> <li>2222</li> <li>3333</li> </ul> <ol slot="ol-slot"> <li>111</li> <li>222</li> <li>333</li> </ol> </aaa> <aaa><aaa> => 这个标签就会显示默认的的情况 </div> <template id="aaa"> <h1>xxxx</h1> <slot name="ol-slot">这是默认的情况1</slot> <p>welcome vue</p> <slot name="ul-slot">这是默认的情况2</slot> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'aaa' }, components:{ 'aaa':{ template:'#aaa' } } }); </script> vue-router(路由)

根据不同url地址,出现不同效果 **注意这是Vue1.0版本** 主页 home 新闻页 news html: </div id="box"> <a v-link="{path:'/home'}">主页</a> 跳转链接 <a v-link="{path:'/news'}">新闻</a> <div> 展示内容: <router-view></router-view> js: //1. 准备一个根组件 var App=Vue.extend(); //2. Home News组件都准备 var Home=Vue.extend({ template:'<h3>我是主页</h3>' }); var News=Vue.extend({ template:'<h3>我是新闻</h3>' }); //3. 准备路由 var router=new VueRouter(); //4. 关联 router.map({ 'home':{ component:Home }, 'news':{ component:News } }); //5. 启动路由 router.start(App,'#box'); //6. 跳转(重定向) router.redirect({ '/':'home' }); 路由嵌套(多层路由)

主页 home 登录 home/login 注册 home/reg 新闻页 news subRoutes:{ 'login':{ component:{ template:'<strong>我是登录信息</strong>' } }, 'reg':{ component:{ template:'<strong>我是注册信息</strong>' } } } 路由其他信息

/detail/:id/age/:age {{$route.path}} -> 当前路径 {{$route.params | json}} -> 当前参数 {{$route.query | json}} -> 数据 ES6: 模块化开发

导出模块: export default {} 引入模块: import 模块名 from '地址' 脚手架

vue-cli——vue脚手架 帮你提供好基本项目结构 模板: 1).webpack 可以使用(大型项目) 1.Eslint 检查代码规范 2.单元测试 2).webpack-simple 个人推荐使用,没有代码检查 √ 基本使用流程: 1. npm install vue-cli -g 安装 vue命令环境 验证安装ok? => vue --version 2. 生成项目模板 vue init <模板名> 本地文件夹名称 3. 进入到生成目录里面 cd xxx npm install 4. npm run dev webpack路由配置

vue-router **注意这是Vue1.0版本** 如何查看版本: bower info vue-router 配合vue-loader使用: 1. 下载vue-router模块 cnpm install vue-router@0.7.13 2. import VueRouter from 'vue-router' 3. Vue.use(VueRouter); // VueRouter基于Vue来开发项目 4. 配置路由 var router=new VueRouter(); router.map({ 路由规则 }) 5. 开启 router.start(App,'#app'); 到了2.0以后,有哪些变化? 在每个组件模板,不再支持片段代码

组件中模板: 之前: <template> <h3>我是组件</h3><strong>我是加粗标签</strong> </template> 现在: 必须有根元素,包裹住所有的代码 <template id="aaa"> <div> <h3>我是组件</h3> <strong>我是加粗标签</strong> </div> </template> 关于组件定义

Vue.extend 1.这种方式,在2.0里面有,但是有一些改动 2.这种写法,即使能用,也不必使用——废弃 Vue.component(组件名称,{ // 在2.0继续能用 data(){ return { } } methods:{} template: }); 2.0推出一个组件,简洁定义方式: var Home={ template:'' -> Vue.extend() }; Vue.component('my-aaa',Home); 生命周期

之前: created 实例已经创建 beforeCompile 编译之前 compiled 编译之后 ready 插入到文档中 => mounted beforeDestroy 销毁之前 destroyed 销毁之后 现在: beforeCreate 组件实例刚刚被创建,属性都没有 created 实例已经创建完成,属性已经绑定 beforeMount 模板编译之前 mounted 模板编译之后,代替之前ready ** beforeUpdate 组件更新之前 updated 组件更新完毕 ** activated 组件被激活时调用(keep-alive) deactivated 组件被移除时调用(keep-alive) beforeDestroy 组件销毁前 destroyed 组件销毁后 循环

2.0里面默认就可以添加重复数据 之前: v-for="(index,val) in array" v-for="(key,val) in json" 现在: v-for="(val,index) in array" v-for="(val,key,index) in json" track-by="$index"

变成: <li v-for="(val,index) in list" :key="index"> 自定义键盘指令

之前: Vue.directive('on').keyCodes.ctrl=17; 现在: Vue.config.keyCodes.ctrl=17 过滤器

之前: 系统就自带很多过滤 {{msg | currency}} {{msg | json}} limitBy filterBy... 到了2.0, 内置过滤器,全部删除了 lodash 工具库 _.debounce(fn,200) 自定义过滤器: 但是,自定义过滤器传参 之前:{{msg | toDou '12' '5'}} 现在:{{msg | toDou('12','5')}} 组件通信

vm.$emit() vm.$on(); 父组件和子组件: 子组件想要拿到父组件数据: 通过 props 之前,子组件可以更改父组件信息,可以是同步 sync 现在,不允许直接给父级的数据,做赋值操作 问题,就想更改: a). 父组件每次传一个对象给子组件,对象之间引用 √ b). 只是不报错,mounted中转 var Event=new Vue(); // 准备一个空的实例对象 import Vue from 'vue'; export default new Vue; Event.$emit(事件名称, 数据) Event.$on(事件名称,function(data){ //data }.bind(this)); 箭头函数写法: Event.$on(事件名称,data=>{ //data }); 可以单一事件管理组件通信: vuex debounce 在Vue2.0被废弃

lodash 工具库 _.debounce(fn,200) vue2.0 动画

transition 之前属性 <p transition="fade"></p> .fade-transition{} .fade-enter{} .fade-leave{} 到2.0以后 transition 组件 <transition name="fade"> 运动东西(元素,属性、路由....) </transition> class定义: .fade-enter{} //初始状态 .fade-enter-active{} //变化成什么样 -> 当元素出来(显示) .fade-leave{} .fade-leave-active{} //变成成什么样 -> 当元素离开(消失) 如何animate.css配合用? <transition enter-active-class="animated zoomInLeft" leave-active-class="animated zoomOutRight"> <p v-show="show"></p> </transition> 多个元素运动: <transition-group enter-active-class="" leave-active-class=""> <p :key="1"></p> <p :key="2"></p> </transition-group> vue2.0 路由

1.布局 <router-link to="/home">主页</router-link> <router-view></router-view> 2.路由具体写法 //组件 var Home={ template:'<h3>我是主页</h3>' }; var News={ template:'<h3>我是新闻</h3>' }; //配置路由 const routes=[ {path:'/home', componet:Home}, {path:'/news', componet:News}, ]; //生成路由实例 const router=new VueRouter({ routes }); //最后挂到vue上 new Vue({ router, el:'#box' }); 3.重定向 之前 router.rediect 废弃了 {path:'*', redirect:'/home'} 4.路由嵌套 /user/username const routes=[ {path:'/home', component:Home}, { path:'/user', component:User, children:[ //核心 {path:'username', component:UserDetail} ] }, {path:'*', redirect:'/home'} ]; 5.路由实例方法 router.push({path:'home'}); // 直接添加一个路由,表现切换路由,本质往历史记录里面添加一个 router.replace({path:'news'}) // 替换路由,不会往历史记录里面添加 6.路由发生变化 watch:{ $route(to,from){ console.log(to,from); //to:到哪里,from:从哪来 console.log(to.path); //可以获取到你点击的路由路径 if(to.path=='/home'){ this.$store.dispatch(''); //发起action }else{ this.$store.dispatch(''); } } } UI组件

目的: 为了提高开发效率 原则: 拿过来直接使用 bootstrap

twitter 开源 简洁、大方 基于 jquery 栅格化系统+响应式工具 elementUI(PC)

官网 http://element.eleme.io/

1.安装 element-ui npm i element-ui -D npm install element-ui --save-dev // i -> install // D -> --save-dev // S -> --save 2.引入 main.js 入口文件 import ElementUI from 'element-ui' import 'element-ui/lib/theme-default/index.css' 3.使用组件 Vue.use(ElementUI) css-loader 引入css 字体图标 file-loader less less less-loader 按需加载相应组件: √ **推荐** 1.babel-plugin-component cnpm install babel-plugin-component -D 2.在.babelrc文件里面新增一个配置 "plugins": [["component", [ { "libraryName": "element-ui", "styleLibraryName": "theme-default" } ]]] 3.想用哪个组件就用哪个 引入: import {Button,Radio} from 'element-ui' 使用: a). Vue.component(Button.name, Button); 个人不太喜欢 b). Vue.use(Button); √ **推荐使用** 数据交互

axios 交互 axios.get(xxx,{}).then(res=>{ // 成功 }).catch(err=>{ // 失败 }) mint-ui(移动端)

官网 http://mint-ui.github.io/

1.下载 npm install mint-ui -S 2.引入 import Vue from 'vue'; import Mint from 'mint-ui'; import 'mint-ui/lib/style.css' Vue.use(Mint); 按需引入: **推荐使用** import { Cell, Checklist } from 'minu-ui'; Vue.component(Cell.name, Cell); Vue.component(Checklist.name, Checklist); 3.中文使用文档 http://mint-ui.github.io/docs/#/zh-cn2 自定义vue全局组件use使用

首先在components中创建一个Loading文件夹,再新建一个index.js文件(位置可自已定义) 再新建一个组件内容文件 => name.vue 以简单的Loading为例: **index.js内容如下**: import LoadingComponent from './Loading.vue' const Loading = { install: function(Vue) { Vue.component('Loading', LoadingComponent) } }; export default Loading **Loading.vue内容如下**: <template> <div class="loading-box"> {{msg}} </div> </template> <script> export default{ data(){ return { msg:'Loading...^_^' } } } </script> <style scoped> .loading-box{ color: red; font-size: 40px; font-family: "微软雅黑"; text-shadow: 2px 2px 5px #000; } </style> **main.js内容如下**: import Loading from './components/loading' Vue.use(Loading) 自定义vue过滤器

首先创建一个filter文件夹,再新建一个index.js文件(位置可自已定义) 再新建一个组件内容文件 => name.vue 以简单的Time为例: **index.js内容如下**: import {Time} from './Time'; export default{ // 可放置多个过滤器组件,中间以逗号隔开 Time }; **Time.js内容如下**: export const Time=(time)=>{ if(time){ let oDate=new Date(); oDate.setTime(time); let y=oDate.getFullYear(); let m=oDate.getMonth()+1; let d=oDate.getDate(); let hh=oDate.getHours(); let mm=oDate.getMinutes(); let ss=oDate.getSeconds(); return y+'-'+two(m)+'-'+two(d)+' '+two(hh)+':'+two(mm)+':'+two(ss); function two(n)=>{ return n<10?'0'+n:''+n; } } } **main.js内容如下**: import filters from './filters' //循环遍历所有的过滤器 Object.keys(filters).forEach(e => Vue.filter(e, filters[e])) 在其他页面使用: {{ 时间 | Time }} 其它设置

1).路由的一些配置 import routes from './routeConfig.js' const router=new VueRouter({ mode: 'history', //切换路径模式,变成history模式 scrollBehavior: () => ({ y: 0 }), routes //引入的路由配置 }); scrollBehavior: () => ({ y: 0 }) 滚动条滚动的行为,不加这个在页面切换时,默认就会记忆原来滚动条的位置 2).axios的一些配置 import axios from 'axios' import store from './store/store' import Loading from './components/Loading' //比如发送请求显示loading,请求回来loading消失之类的 axios.interceptors.request.use(function (config) { //配置发送请求的信息 store.dispatch('showLoading') return config; }, function (error) { return Promise.reject(error); }); axios.interceptors.response.use(function (response) { //配置请求回来的信息 store.dispatch('hideLoading') return response; }, function (error) { return Promise.reject(error); }); //设置post请求头部信息 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; //配置请求根路径 axios.defaults.baseURL='http://localhost:8080/'; //把axios对象挂载到Vue的原型上,其他页面在使用axios的时候直接this.$http就可以了 Vue.prototype.$http = axios; 使用less

安装less loader npm install less-loader less --save-dev 在style标签里加上lang="less" <style lang="less"></style> 用官方脚手架(vue-cli)搭建环境无法调起浏览器

找到config文件夹里的index.js 将 autoOpenBrowser: false, 修改为 autoOpenBrowser: true, node获取本机ip

// https://stackoverflow.com/questions/3653065/get-local-ip-address-in-node-js function getIPAddress() { var interfaces = require("os").networkInterfaces(); for (var devName in interfaces) { var iface = interfaces[devName]; for (var i = 0; i < iface.length; i++) { var alias = iface[i]; if (alias.family === "IPv4" && alias.address !== "127.0.0.1" && !alias.internal) { return alias.address; } } } return "0.0.0.0"; } 安装swiper

npm i swiper -D //引入swiper import Swiper from 'swiper'; //引入swiper.css //注意:以组件名称开始向内部依次寻找css文件 import 'swiper/dist/css/swiper.min.css'; //将swiper挂载到Vue的原型上,后续直接使用this.swiper可以了 Vue.prototype.Swiper = Swiper; div模拟textarea文本域实现高度自适应以及输入纯文本

<div contenteditable="true"></div> 与contenteditable属性无关的CSS控制法 user-modify: write-only; user-modify: read-write-plaintext-only; read-write和read-write-plaintext-only会让元素表现得像个文本域一样,可以focus以及输入内容 由此延伸: 最近要在移动端做一套关于问卷的活动,第一个想到的是用div来模拟textarea, 其中会用到contenteditable="true"的属性来达到可输入文本的功能(用在移动端足够) 然后通过vue的v-on:input="updata($event)" => @input="updata($event)"来实时获取用户输入的文字 如何让contenteditable元素只能输入纯文本,可参考以下文章

张鑫旭博客:如何让contenteditable元素只能输入纯文本

oninput和onchange的区别

oninput事件类似于 onchange事件 不同之处在于oninput事件在元素值发生变化是立即触发,onchange在元素失去焦点时触发 keymirror插件的使用

npm i keymirror -S 在使用vuex的时候,我们通常要建一个mutation-type.js来专门来放mutation里用到的方法常量值 此做法是为了方便多人协作的时候不至于代码太乱,所以要放在一个文件里统一管理

正常的写法

export const START = 'START';

加入keymirror之后的写法

import keymirror from 'keymirror'; let types = keymirror({ START:null }) export {types}; 地址栏参数获取

//地址栏参数获取1 getUrlData(name){ let urlHref = window.location.href; let urlObj = {}; if (urlHref.indexOf('?')!=-1) { let getArr = urlHref.split('?')[1].split('&'); getArr.forEach(e => { if (!(e.split('=')[0] in urlObj)) { urlObj[e.split('=')[0]] = e.split('=')[1]; } }) for(let key of Object.keys(urlObj)){ urlObj[key] && (urlObj[key] = decodeURIComponent(urlObj[key].replace(/#\//,''))) } return urlObj[name]; }else return null; } //地址栏参数获取2 const querystring=require('querystring');//引入node系统模块 getUrlData(name){ let urlHref = window.location.href; if (urlHref.indexOf('?')!=-1) { let getStr = urlHref.split('?')[1]; let urlObj = querystring.parse(getStr); for(let key of Object.keys(urlObj)){ urlObj[key] && (urlObj[key] = decodeURIComponent(urlObj[key].replace(/#\//,''))) } return urlObj[name]; }else return null; } //地址栏参数获取3 getQuery (name) { let reg = new RegExp("([&,?])" + name + "=([^&]*)(&|$)", "i"); let r = window.location.search.match(reg) || window.location.hash.match(reg); if (r != null) return decodeURIComponent(r[2]); return null; } 滚动Demo

利用vue的transition-group来实现动画 .fade-enter-active{} //变化成什么样 -> 当元素出来(显示) .fade-leave-active{} //变成成什么样 -> 当元素离开(消失)

点此查看示例Demo

state状态存储插件

vuex状态存储插件

import Vue from 'vue' import Vuex from 'vuex' import mutations from './mutations' import actions from './actions' import VuexPersistence from 'vuex-persist' Vue.use(Vuex) // 存储至localStorage /* const vuexStorage = new VuexPersistence({ storage: window.localStorage }) */ // 存储至sessionStorage const vuexStorage = new VuexPersistence({ storage: window.sessionStorage }) export default new Vuex.Store({ modules:{ mutations }, actions, plugins: [vuexStorage.plugin] }) Vue-Socket.io插件的使用

安装 npm install vue-socket.io -S 引入 import VueSocketio from 'vue-socket.io'; Vue.use(VueSocketio, 'http://www.baidu.com');

sockets: { connect() { console.log('socket已连接') }, getInfo(val) {//接收消息 console.log('接收到服务端消息', val) } }, methods: { addSocket() { //向服务端发送消息 this.$socket.emit('commitInfo', '我收到消息了'); } } 加减分实践

let n = 0;//初始值 res.data.forEach(e => { if (e.type == 1) {//加分 e.sum = n + Number(e.num); n += Number(e.num); } else {//减分 e.sum = n - Number(e.num); n -= Number(e.num); } }) res.data.sort((a, b) => b.id = a.id) this.list = res.data; $set的使用

引自vue官方文档:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新 那么这个时候你就需要$set,就是这样...比较类似于原生的自定义属性 import * as obj

按 es6 的规范 import * as obj from "xxx" 会将 "xxx" 中所有 export 导出的内容组合成一个对象返回 倒计时方法

this.time = Math.floor((new Date(res.Body.EndTime) - new Date()) / 1000); // console.log(this.time) this.timer = setInterval(_ => { this.time--; if (this.time === 0) { clearInterval(this.timer) } }, 1000) computed: { getTime: function() { function two(n) { return n < 10 ? '0' + n : '' + n; } let d = two(Math.floor(this.time / 86400)) let h = two(Math.floor(this.time % 86400 / 3600)) let s = two(Math.floor(this.time % 3600 / 60)) let m = two(Math.floor(this.time % 60)) // console.log(d + '天' + h + '时' + s + '分' + m + '秒') return this.time == null ? `正在计算时间...` : this.time > 0 ? `结束倒计时:${h}时${s}分${m}秒` : `活动已结束`; }, } 设备判断

//获取浏览器版本 Versions: function () { var u = navigator.userAgent, app = navigator.appVersion; return { trident: u.indexOf('Trident') > -1, //IE内核 presto: u.indexOf('Presto') > -1, //opera内核 webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核 gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核 mobile: !!u.match(/AppleWebKit.*Mobile.*/) || !!u.match(/AppleWebKit/), //是否为移动终端 ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端 android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器 iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器 iPad: u.indexOf('iPad') > -1, //是否iPad webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部 weiXin: u.indexOf('MicroMessenger') > -1 //是否是微信 } }, 使用vue-router设置每个页面的title

routes: [ { path: '/', name: 'Index', component: Index, meta: { title: '首页' } }, { path: '/user', name: 'User', component: User, meta: { title: '我的' } } ]

在每一个meta里面设置页面的title名字

router.beforeEach((to, from, next) => { /* 路由发生变化修改页面title */ if (to.meta.title) { document.title = to.meta.title } next() })

vue-wechat-title(解决Vuejs 单页应用在iOS系统下部分APP的webview中 标题不能通过 document.title = xxx 的方式修改)

使用方法参考链接

vue项目做seo

对于vue、react这类项目而言,它们的开发思想使得我们能真正做到前后端分离、解耦。单页面的使用给用户带来了更好体验,但是存在首屏加载慢、白屏以及SEO等问题。那么该如何解决这些问题?

1.SSR 注:不是酸酸乳啦,而是Server-side rendering(服务端渲染)

2.Prerendering

1.SSR服务端渲染

这似乎又回到了之前的开发模式,前端和后端还是紧密联系在一起了,给维护和迭代带来的不便。至于优点,请参考  服务端渲染(SSR),可点击

2.Prerendering

预渲染相对于SSR比较简单,且预渲染可以极大的提高网页访问速度。可以利用第三方插件prerender-spa-plugin,在客户端实现渲染。prerender-spa-plugin 是webpack的插件,它可以编译应用中的所有静态页面,轻而易举的建立对应的索引路径。怎样使用呢?(以vue-cli3为例,适用于页面较少的项目)

1).安装

npm install prerender-spa-plugin -D

2).使用

//vue.config.js文件 const PrerenderSPAPlugin = require('prerender-spa-plugin'); const Renderer = PrerenderSPAPlugin.PuppeteerRenderer; if(process.env.NODE_ENV === 'production'){ plugins.push( new PrerenderSPAPlugin({ // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示 staticDir: path.join(__dirname, process.env.VUE_APP_OUTPUT_DIR), // 对应自己的路由文件,比如index有参数,就需要写成 /index/param1 routes: ['/', '/home','/about'], // html文件压缩 minify: { minifyCSS: true,// css压缩 removeComments: true// 移除注释 }, // 如果没有配置这段,也不会进行预编译 renderer: new Renderer({ // 不打开chromium浏览器 headless: false, // 在main.js中配置document.dispatchEvent(new Event('render-event')) renderAfterDocumentEvent: 'render-event' }) }) ) }

在vue.config.js文件配置之后,还需要在main.js文件中添加以下代码:

// ./src/main.js文件 new Vue({ router, render: h => h(App), mounted () { // 你需要这个用于 renderAfterDocumentEvent document.dispatchEvent(new Event('render-event')) } }).$mount('#app');

prerender-spa-plugin插件是需要依赖puppeteer的,也就是谷歌出品的无头浏览器插件,这个插件会下载最新版的chromium(大约200M+),如果不能科学上网,就会报错。

执行 npm run build 就会生成预渲染的html,至于具体的配置项,可移步至 github仓库https://github.com/chrisvfritz/prerender-spa-plugin

注意:预渲染要求是histroy模式,否则生成的页面都是同一个html

// .src/router/index.js文件 export default new vueRouter({ mode:"history", // history模式 routes }) 3.在vue中使用 vue-meta-info

1).安装

npm install vue-meta-info -D

2).引入

// ./src/main.js文件 import MetaInfo from 'vue-meta-info' Vue.use(MetaInfo)

3).使用

// ./src/xx/xx.vue文件 export default { metaInfo: { title: '我是title', meta: [ { name: 'keywords', content: '好嗨呦' }, { name: 'description', content: '太阳好圆啊' } ] } }

参考文档:

1.vue项目做seo(prerender-spa-plugin预渲染)

2.利用prerender-spa-plugin提升单页面应用的体验

CDN可配置

//vue.config.js文件 // 打包排除某些依赖 const externals = { vue: 'Vue', axios: 'axios' } // cdn资源 const cdn = { // 开发环境 dev: { css: [], js: [] }, // 生产环境 build: { css: [], js: [ 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js', 'https://cdn.jsdelivr.net/npm/axios@0.19.0/dist/axios.min.js' ] } }

怎么用?

//vue.config.js文件 chainWebpack: config => { // 添加CDN参数到htmlWebpackPlugin配置中,详见public/index.html修改 // 参考链接https://cli.vuejs.org/zh/guide/webpack.html#修改插件选项 config.plugin('html').tap(args => { args[0].cdn = process.env.NODE_ENV === 'production'? cdn.build : cdn.dev; return args })   }, configureWebpack: config => { if (process.env.NODE_ENV === 'production') { // externals里的模块不打包 Object.assign(config, {externals}) } else { // 开发环境配置... } },

然后呢?

<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- dns预解析 --> <link rel="dns-prefetch" href="//<%= VUE_APP_PROJECT_URL %>" /> <meta name="format-detection" content="telephone=no" /> <meta name="format-detection" content="email=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="full-screen" content="yes"> <meta name="browsermode" content="application"> <meta name="x5-orientation" content="portrait"> <meta name="x5-fullscreen" content="true"> <meta name="x5-page-mode" content="app"> <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui"> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <!-- 使用CDN加速的CSS文件,配置在vue.config.js下 --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" /> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" /> <% } %> <title>vue-cli3</title> </head> <body> <div id="app"></div> <!-- 使用CDN加速的JS文件,配置在vue.config.js下 --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %> </body> </html> 移动端开发环境加入vConsole

configureWebpack: config => { if (process.env.NODE_ENV === 'production') { // 生产环境配置... if (process.env.npm_config_report) { // 打包后模块大小分析 npm run build --report const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; config.plugins.push(new BundleAnalyzerPlugin()) } } else { // 开发环境配置... // https://github.com/diamont1001/vconsole-webpack-plugin config.plugins.push( new vConsolePlugin({ filter: [], // 需要过滤的入口文件 enable: true // 发布代码前记得改回 false }) ) } },

这样就可以愉快的在开发环境使用vConsole

生产环境去除hash

configureWebpack: config => { if (process.env.NODE_ENV === 'production') { //生产环境去除hash Object.assign(config.output, { filename: 'js/[name].js', chunkFilename: 'js/[name].js' }) } else { // 开发环境配置... } }, 参考链接

1.DNS 预读取

2.JSP示例文档

vue-cli3执行dev打开两次浏览器问题

应该是官方脚手架的问题,将vue.config.js文件里devServer配置的open选项注释掉, package.json里面dev命令改为:"dev": "vue-cli-service serve --open"即可解决 在 Chrome Devtools 中展示源代码

configureWebpack: { devtool: 'source-map' } //vue cli3 configureWebpack: config => { if (process.env.NODE_ENV === 'production') { }else{ config['devtool'] = 'source-map'; } }

webpack的devtool文档,请戳我

版权声明:

1、该文章(资料)来源于互联网公开信息,我方只是对该内容做点评,所分享的下载地址为原作者公开地址。
2、网站不提供资料下载,如需下载请到原作者页面进行下载。