vue插件
Vue.js提供了插件机制,可以在全局添加一些功能。它们可以简单到几个方法、属性,也可以很复杂,比如一整套组件库。
注册插件需要一个公开的方法install,它的第一个参数是Vue构造器,第二个参数是一个可选的选项对象。示例如下:
MyPlugin.install = function(Vue,options){
//全局注册组件(指令等功能资源类似)
Vue.component('component-name',{
//组件内容
});
//添加实例方法
Vue.prototype.$Notice = function() {
//逻辑。。。
};
//添加全局混合
Vue.mixin({
mounted:function() {
//逻辑。。
}
})
}
通过Vue.use(MyPlugin)或者
Vue.use(MyPlugin,{
//参数
})
来使用插件。绝大多数情况下,开发插件主要是通过NPM发布后给别人使用的。在自己的项目中可以直接在入口调用以上的方法。
前端路由
webpack主要使用场景是单页面富应用(SPA),而SPA的核心就是前端路由。什么是路由,通俗的讲就是网址。专业一点就是每次get或post等请求在服务端有一个专门的正则配置列表,然后匹配到具体的一条路径后,分发到不同controller,进行各种操作,最终将html或数据返回给前端,这就完成了一侧IO。
目前绝大多是的网站都是后端路由,也就是多页面的,这样的好处很多,比如可以在服务端渲染好直接返回给浏览器,不用等待前端加载任何js和css就可以直接显示网页内容,对SEO的友好等。缺点也很明显,就是模板由后端累维护或改写html结构,所以html和数据、逻辑混为一谈,维护起来臃肿麻烦。
然后就有了前后端分离的开发模式。后端只提供API来返回数据,前端通过AJAX请求获取数据,在用一定的方式渲染都页面中。这样出现很多前端技术栈,比如jQuery + artTemplate +requirejs + gulp为主的开发模式可谓是万金油了。
在Node.js出现后,这种现象有了改善,html模板可以完全由前端累控制,同步或异步渲染完全由前端自由决定,并且由前端维护一套模板。
SPA就是在前后端分离的基础上加上路由。
vue-router的基本用法
新建一个项目router,复制上一章代码并安装完成后,再通过NPM来安装vue-router:
npm install --save vue-router
在main.js里使用Vue.use()加载插件:
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue';
Vue.use(VueRouter);
每个页面对应一个组件,也就是对应一个.vue文件。在router目录下创建views目录,用于存放所有页面,然后在views里创建index.vue和about.vue两个文件:
// index.vue
<template>
<div>首页</div>
</template> <script>
export default { }
</script> <style scoped> </style>
// about.vue
<template>
<div>介绍页</div>
</template> <script>
export default { }
</script> <style scoped> </style>
回到main.js完成路由剩余配置,创建一个数组来制定路由匹配列表,每一个路由映射一个组件:
const Routers = [
{
path: '/index',
component: (resolve) => require(['./views/index.vue'],resolve)
},
{
path: '/about',
component: (resolve) => require(['./views/about.vue'],resolve)
}
]
Routers里每一项的path属性就是指定当前匹配的路径 ,component 是映射的组件。上面的写法,webpack会把每个路由都打包为一个js文件,在请求到该页面时,才回去加载这个页面的js,也就是异步实现的懒加载。如果想要一次性加载,可以这样写:
{
path: '/about',
component: require(['./views/index.vue'])
}
使用异步路由后,便一处的每个页面的js都叫做chunk(块),它们命名默认是0.main.js、1.main.js....可以在webpack配置出口里通过设置chunkFilename字段修改chunk命名,例如:
output:{
publicPath:'/dist/',
filename: '[name].js',
chunkFilename: '[name].chunk.js'
}
有了chunk后,在每个页面(.vue文件)里写的样式也需要配置后才会打包进main.css,否则仍然会通过javascript动态创建<style>标签写入,配置插件:
//webpack.config.js plugins: [
new ExtractTextPlugin({
filename:'[name].css',
allChunk:true
})
]
然后继续在main.js里完成配置和路由实例:
const RouterConfig = {
//使用html5的history路由模式
mode: 'history',
routes: Routers
}; const router = new VueRouter(RouterConfig); //创建Vue实例
new Vue({
el: "#app",
router: router,
render: h => h(App)
});
在RouterConfig里,设置mode为history会开启HTML5的history路由模式,通过"/"设置路径。如果不配置mode,就会使用"#"来设置路径。开启history路由,在生产环境时服务端必须进行配置,将所有路由都指向同一个html。
webpack-dev-server也要配置下来支持history路由,在package.json中修改dev命令:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open --history-api-fallback --config webpack.config.js",
"build": "webpack --mode production"
},
增加了-history-api-fallback,所有的路由都会指向index.html。
配置好了这些,最后在app.vue添加一个<router-view>来挂载所有路由组件:
<template>
<div>
<router-view></router-view>
</div>
</template> <script> export default { }
</script> <style scoped>
div {
color: #f60;
font-size: 24px;
}
</style>
运行网页时,<router-view>会根据当前路由动态渲染不同的页面组件。网页中的一些公共部分,比如顶部的导航栏,侧边导航栏,底部的版权信息,这些也可以直接写在app.vue里,与<router-view>同级。路由切换时,切换的是<router-view>挂载的组件,其他内容并不会变化。
运行npm run dev启动服务,然后访问127.0.0.1:8080/index和127.0.0.1/about就可以访问这两个页面了。
在列表里,可以在最后新加一项,当访问路径不存在时,重定向到首页:
{
path: '*',
redirect: '/index'
}
路由列表的path也可以带参数,比如“个人主页”的场景,路由的一部分时固定的,一部分时动态的:/user/123456,其中用户id"123456"就是动态的,但是路由到同一个页面,这个页面需要获取到这个id,请求对应的数据,在路由里可以这样配置参数:
{
path: '/user/:id',
component: (resolve) => require(['./views/user.vue'],resolve)
},
在views目录下新建user.vue文件
<template>
<div>{{$route.params.id}}</div>
</template> <script>
export default {
mounted () {
console.log(this.$route.params.id);
}
}
</script> <style scoped> </style>
这里的this.$router可以访问到当前路由的很多信息。
跳转
vue-router有两种跳转页面的方法,第一种是内置的<router-link>组件,它会被焕然成一个a标签。
<template>
<div>
<h1>首页</h1>
<router-link to="/about">跳转到about</router-link>
</div>
</template>
用法和一般的组件一样,to是一个prop,指定需要跳转的路径,也可用v-bind来绑定动态设置。在html5的histtory模式下会拦截点击,避免浏览器重新加载页面。<router-link>还有其他一些prop,常用的有:
tag
tag可以指定渲染成什么标签,比如<router-link to='/about' tag='li'></router-link>渲染的结果就是<li>
replace
使用replace不会留下history记录,所以导航后不能后退返回上一个页面,<router-link to='/about' replace>
active-class
当router-link 对应的路由匹配成功时,会自动给当前元素设置一个名为router-link-active的clas,设置prop:active-class可以修改默认的名称。在做类似的导航栏时,可以使用该功能高亮显示当前页面对应的导航菜单项,但是一个不修改active-class
如果跳转需要在javascript里进行,可以使用第二种方法
<template>
<div>
<h1>介绍页</h1>
<button @click="handleRouter">跳转到user</button>
</div>
</template> <script>
export default { methods:{
handleRouter() {
this.$router.push('/user/123')
} }
}
</script> <style scoped> </style>
添加点击事件,this.$router.push就可以。
$router还有一些其他的方法:
replace
this.$router.replace('/user/123'),替换当前的history记录。
go
类似前进和后退多少步。
this.$router.go(-1);
高级用法
如何修改网页标题?
vue-router提供了导航钩子beforeEach和afterEach,它们会在路由即将改变前和改变和触发,所以设置标题可以在beforeEach钩子完成。
const Routers = [
{
path: '/index',
meta:{
title:'首页'
},
component: (resolve) => require(['./views/index.vue'],resolve)
},
{
path: '/about',
meta:{
title:'关于'
},
component: (resolve) => require(['./views/about.vue'],resolve)
},
{
path: '/user/:id',
meta:{
title:'个人主页'
},
component: (resolve) => require(['./views/user.vue'],resolve)
},
{
path: '*',
redirect: '/index'
}
]; const RouterConfig = {
//使用html5的history路由模式
mode: 'history',
routes: Routers
}; const router = new VueRouter(RouterConfig);
router.beforeEach((to, from, next) => {
window.document.title = to.meta.title;
next();
console.log('before')
});
导航钩子有三个参数:
to 即将要进入的目标路由对象。
form 当前导航即将要离开的路由对象。
next 调用该方法后,才能进入下一个钩子。
路由列表的meta字段可以自定义一些信息,比如将title写入了meta来统一维护,beforeEach钩子可以从路由对象to里获取meta信息,从而改变标题。
有了这两个钩子,还能做很多来提升用户体验。比如页面较长,滚动到某个位置,在跳到另一个页面,滚动条默认实在上一个页面停留的位置,而最好是能返回顶部,通过钩子afterEach就可以实现
router.afterEach((to,from,next) => {
window.scroll(0,0)
})
类似的需求还有从一个页面过度到另一个页面时,可以吹安一个全局的loading动画。到新页面加载完成后再结束动画。
next()方法还可以设置参数。
某些页面需要检验是否登录,登录了就可以访问,不然就打登录页面。
router.beforeEach((to,form,next) => {
if(window.localStorage.getItem('token')){
next();
}else{
next('/login');
}
})
状态管理与Vuex
非父子组件通信时,使用了bus的一个方法,用来触发和接收事件,进一步起到了通信的作用。Vuex所解决的问题与bus类似,作为一个插件来使用,可以更好的维护整个项目的组件状态。
Vuex的基本用法
npm install --save vuex
用法和vue-router类似,在main.js里,通过Vue.use()使用Vuex。
import Vuex from 'vuex'
Vue.use('Vuex')
const store = new Vuex.Store({
//vuex配置
})
new Vue({
el: "#app",
router: router,
store:store,
render: h => h(App)
});
仓库store包含了应用的数据和操作过程。Vuex里的数据都是响应式的,任何组件使用同一store的数据时,只要store的数据变化,对应的组件也会立即更新。
数据保存在Vuex选项的state字段内,实现一个计数器,定义一个count,初始值为0:
const store = new Vuex.Store({
state: {
count:0
},
})
在任何组件内,可以直接通过$store.state.count读取:
<template>
<div>
<h1>首页</h1>
{{count}}
</div>
</template>
<script>
export default {
computed: {
count () {
return this.$store.state.count;
}
}
}
mutations是Vuex的第二个选项,用来直接修改state里的数据。我们给计数器增加2个mutations,用来加1或者减1
const store = new Vuex.Store({
state: {
count:0
},
mutations: {
increment (state) {
state.count ++;
},
decrease (state) {
state.count --;
}
},
})
然后在组件内,通过this.$store.commit方法来执行mutations。在index.vue中添加按钮用于加和减:
<template>
<div>
<h1>首页</h1>
{{ count }}
<button @click="handleIncrement">+1</button>
<button @click="handleDecrease">-1</button>
</div>
</template>
<script>
export default {
computed:{
count () {
return this.$store.state.count;
},
},
methods: {
handleIncrement () {
this.$store.commit('increment');
},
handleDecrease () {
this.$store.commit('decrease');
},
}
}
</script>
<style scoped> </style>
mutations还可以接受第二个参数,可以是数字、字符串或对象等类型。
increment (state, n=1) {
state.count += n;
},
然后在组件里面
handleIncrement () {
this.$store.commit('increment', 5);
},
高级用法
Vuex还有其他3个选项可以使用:getters、actions、modules。
const store = new Vuex.Store({
state: {
count:0
},
getters: {
filteredList: state => {
return state.list.filter(item => item < 10);
},
listCount: (state, getters) => {
return getters.filteredList.length;
}
},
}) //getters可以写一些通用的方法在里面,方便各个组件使用
<template>
<div>
<h1>首页</h1>
<div>{{ list }}</div>
<div>{{listCount}}</div>
</div>
</template> <script>
export default {
computed:{
count () {
return this.$store.state.count;
},
list () {
return this.$store.getters.filteredList;
},
listCount () {
return this.$store.getters.listCount;
}
},
}
</script> <style scoped> </style>
getters也可依赖其他的getter,把getter作为第二个参数。
mutationi不应该异步操作数据,所以有了actions选项。action与mutation很像,不同的是action里面提交的是mutation。并且可以异步操作业务逻辑。
action在组件内通过$store.dispatch触发,主要在异步的时候使用。
actions: {
asyncIncrement (context) {
return new Promise(resolve => {
setTimeout(() => {
context.commit('increment');
resolve();
},1000)
})
}
}
handleActionIncrement () {
this.$store.dispatch('increment').then(() => {
console.log(this.$store.state.count);
})
}
mutations、actions看起来很相似,Vuex很像是一种与开发者的约定,涉及改变数据的使用mutations,存在业务逻辑的就用actions。
最后一个选项是modules,它用来将store分给到不同的模块中。当项目足够大时,store里的state、getters、mutations、actions会非常多,都放在main.js不是很好,使用modules可以将它们写到不同的文件中,每个module拥有自己的state、getters、mutatios、actions,而且可以多层嵌套。
const moduleA = {
state:{....},
mutations:{.....},
actions:{....},
getters:{.....}
}
const moduleB = {
state:{....},
mutations:{.....},
actions:{....},
getters:{.....}
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a //moduleA的状态
store.state.b //moduleB的状态
const moduleA = {
state: {
count:0
},
getters: {
sumCount (state, getters, rootState) {
return state.count + rootState.count;
}
}
}
module的mutation和getter接收的第一个参数state是当前模块的状态。在actions和getters中,还可以接收一个参数rootState,来访问根节点的状态。
vue插件的更多相关文章
- vue插件编写与实战
关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 热爱vue开发的同学肯定知道awesome-vue 这个github地址,里面包含了数以千计的vue ...
- 第一个Vue插件从封装到发布
前言 这是我封装的第一个Vue插件,实现的功能是滑动选择省市区,虽然只是一个简单的插件,但还是挺开心的,记录一下步骤. 插件地址:https://github.com/leichangchun/vue ...
- 手把手教你写vue插件并发布(二)
前记:上一篇 https://www.cnblogs.com/adouwt/p/9211003.html, 说到了一个完整的vue插件开发.发布的流程,总结下来就讲了这么一个事,如何注入vue, 如果 ...
- VUE插件大总结
UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开 ...
- vue插件大全汇总
Vue是一个构建数据驱动的 web 界面的渐进式框架.Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件特别整理了常用的vue插件,来了个大汇总,方便查找使用,便于工作 ...
- VUE插件总结
亲们支持我的新博客哦==>地址(以后更新会尽量在新博客更新,欢迎大家访问加入我的后宫w) ) UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和W ...
- Vue插件plugins的基本操作
前面的话 本文将详细介绍Vue插件plugins的基本操作 开发插件 插件通常会为 Vue 添加全局功能.插件的范围没有限制——一般有下面几种: 1.添加全局方法或者属性,如: vue-custom- ...
- 把axios封装为vue插件使用
前言 自从Vue2.0推荐大家使用 axios 开始,axios 被越来越多的人所了解.使用axios发起一个请求对大家来说是比较简单的事情,但是axios没有进行封装复用,项目越来越大,引起的代码冗 ...
- Vue插件写、用详解(附demo)
出处http://blog.csdn.net/qq20004604 Vue插件 1.概述 简单来说,插件就是指对Vue的功能的增强或补充. 比如说,让你在每个单页面的组件里,都可以调用某个方法,或者共 ...
- 推荐 VSCode 上特别好用的 Vue 插件 - vetur
作者 @octref 此前 V2EX 发过帖子,最近新增代码补全功能,综合比较应该是目前 VSCode 上面最好用的 Vue 插件. 能够实现在 .vue 文件中: 语法错误检查,包括 CSS/SCS ...
随机推荐
- redis数据库-VUE创建项目
redis数据库 ''' 关系型数据库: mysql, oracle 非关系型数据库(nosql): redis,mongodb (没有表的概念) key-value mongodb: json 数据 ...
- os.path官方文档(附翻译)
This module implements some useful functions on pathnames. To read or write files see open(), and fo ...
- 关于Url路径中出现特殊字符,文件无法下载的问题
1.原网址 传送门:http://blog.csdn.net/jackljf/article/details/43796137 在站点根目录新建或编辑web.config 文件,找到<syst ...
- GoLand配置数据库、远程host以及远程调试
GoLand配置MySQL数据库: (1)右侧栏 -> Database -> +添加 (2)选择MySQL (3)修改Name -> Comment(可选) (4)选择MySQL版 ...
- 什么样的类才算是一种可重用的组件,即JavaBean?
每一个类实现了Bean的规范才可以由Spring来接管,那么Bean的规范是什么呢? 必须是个公有(public)类 有无参构造函数 用公共方法暴露内部成员属性(getter,setter) 实现这样 ...
- VMware虚拟机开机自启动
VMware虚拟机开机自启动 linux 2018年05月09日 08时30分18秒 VMware的命令行语句可以切换到VMware安装目录,使用vmrun.exe --help(windows下)查 ...
- 【webpack学习笔记】a02-管理资源
在webpack 中,各种资源要引入,要用到module配置,比如css/图片/字体等等. 例如: module.exports = { entry: './src/app.js', //这是入口文件 ...
- h264文件分析(纯c解析代码)
参考链接:1. 解析H264的SPS信息 https://blog.csdn.net/lizhijian21/article/details/80982403 2. h.2 ...
- js初学
1.学习一门编程语言需要记住知识点: 1.关键字. 2.标识符. 3.注释. 4.运算符. 5.常量和变量 . 6.语句. 7.函数 ...
- java 的序列化与反序列化
前言: 一直很不理解java的序列化的概念,为什么java对象的序列化要实现 Serializable的接口?或者要实现Externalizable的接口?而且Externalizable 的父类还是 ...