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 ...
随机推荐
- js删除数组中元素 delete 和splice的区别
例如我有一个数组: var array = ["aa","dd","cc","aa"] ,我想删除这个数组的“dd”元素 ...
- sql习题及答案
sql习题:http://www.cnblogs.com/wupeiqi/articles/5729934.html 习题答案参考:https://www.cnblogs.com/wupeiqi/ar ...
- DBLookupCombobox实现下拉联动
这次用DBLookupCombobox实现省份-城市-地区的下拉联动,用以学习DBLookupCombobox的一些用法 效果图: 首先建立数据表(数据表形式可以多种多样:数据库表.文本.xml等,最 ...
- 阅读github上的项目源码
1.基础资料 函数手册,类库函数手册2.和程序相关的专业资料 高数,linux文件系统3.相关项目的文档资料4.留备份,构造可运行的环境,找开始的地方 main(),5.分层次阅读,写注解,编程思想, ...
- week7
catalog 1.面向对象 2.类的继承(续):直接继承与间接继承 3.类方法.静态方法.属性方法 4.getitem 5.反射 6._new_\_metaclass_ 7.异常处理 1.面向对象 ...
- Html+css学习笔记一 创建一个网页
第一个网页 新建一个记事本,把名字改成first.html <html> <head> <title>MyFristHtml</title> </ ...
- 操作日志的设计小结by大熊
一.首先由同事的操作日志说起 同事做了一个这样的操作日志,他定义系统所有发的json加入这两个字段,module和msg,然后在service里面用注解@Log拦截,即可记录对应的操作日志. { mo ...
- # -*- coding: utf-8 -*-
-- coding: utf-8 -- import scrapy from jobscrawler_qianchengwuyou.items import JobscrawlerQianchengw ...
- 201671010142 2017-2 《java第十二十三章学习感悟》
Swing编程第一步,需要导入Swing相关包,即javax.swing.*. 接下里需要设置界面外观风格,使用到UIManager类. 设置完外观之后一定要调用 SwingUtilities.upd ...
- angularjs i18n
<!doctype html><html ng-app="myApp"><head> <meta charset="utf ...