渐进式 JavaScript 框架
一个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(服务端渲染)
1.SSR服务端渲染2.Prerendering
这似乎又回到了之前的开发模式,前端和后端还是紧密联系在一起了,给维护和迭代带来的不便。至于优点,请参考 服务端渲染(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 }) ) } },
生产环境去除hash这样就可以愉快的在开发环境使用
vConsole
了
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、网站不提供资料下载,如需下载请到原作者页面进行下载。