基于vue-cli 建立一个模板项目 经过 npm root -g 能够查看vue全局安装目录,进而知道本身有没有安装vue-cli 若是没有安装的话,使用以下命令全局安装 cnpm install -g vue-cli 建立一个基于webpack的新项目,在这过程当中, 会安装依赖 vue init webpack 项目名 启动 cd vue-router-demo npm start
若是咱们的项目是经过脚手架搭建的,这已是一个比较完善的种子项目了css
|-- build : webpack 相关的配置文件夹(基本不须要修改) |-- config: webpack 相关的配置文件夹(基本不须要修改) |-- index.js: 指定的后台服务的端口号和静态资源文件夹 |-- node_modules: 在上面安装的依赖,都存放在这个文件夹下 |-- src : 源码文件夹,咱们后续开发的组件和js分门别类的放在这里面 |-- main.js: 应用入口 js |-- static: 静态资源文件夹 |-- .babelrc: babel 的配置文件 |-- .editorconfig: 经过编辑器的编码/格式进行必定的配置 |-- .eslintignore: eslint 检查忽略的配置 |-- .eslintrc.js: eslint 检查的配置 |-- .gitignore: git 版本管制忽略的配置 |-- index.html: 主页面文件 |-- package.json: 他就至关于maven的pom.xml, 里面存放着相关的依赖信息和项目的版本信息 |-- README.md: 应用描述说明的 readme 文件
能够在config/index.js中作一下的经常使用配置html
在开发的时候咱们主要仍是关注src文件, 后来须要的路由,store,ajaxApi,以及其余组件所有在建立在这个文件夹下vue
const path = require('path') module.exports = { dev: { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: {}, //添加跨域的配置 // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST port: 9528, // 配置是否打开浏览器 autoOpenBrowser: true, //配置是否打开浏览器 errorOverlay: true, notifyOnErrors: false, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- // Use Eslint Loader? // If true, your code will be linted during bundling and // linting errors and warnings will be shown in the console. useEslint: false, // If true, eslint errors and warnings will also be shown in the error overlay // in the browser. showEslintErrorsInOverlay: false,
通常作好这不配置以后main就不用再改动了node
import App from './App' import router from './router' import store from './store' Vue.use(ElementUI, { locale }) new Vue({ el: '#app', router, store, template: '<App/>', components: { App } })
其实每个组件均可以完整的拥有下面三部分, 固然若是哪一个组件中不须要添加css样式,能够把最后一个style或者script标签去掉webpack
<template> <div> <!-- 这里存放 --> </div> </template> <//script> export default { name: 'app' } <///script> <style> </style>
好比根组件想使用hello.vue组件,怎么作呢?ios
像下面这样,三步走git
<template> <div> <!--第三步使用标签--> <hello/> <div/> <template/> <script> import hello form './XXX/hello.vue' export default{ // 将组件映射成标签 components:{ hello } } <style> </style>
第二步中引入标签时也能够去掉.vue后缀web
或者直接这样写,是从@/ 表明的是 src/ajax
import hello form '@/XXX/hello'
npm run build
项目通过打包,产出是一个dist文件,里面分别是index.html 和 静态资源文件夹, 这也是先后端分离开发的特点,后端想控制view层,也难了,只有一张index.htmlvue-router
命令:
npm install -g serve // 安装工具 serve dist
注意点,使用tomcat当服务器,要求文件夹的名字和项目的名字要同样,修改的步骤以下:
/build/webpack_prod.conf.js
文件output:{ ... pathPath:'项目名称' }
npm run build
好的习惯就是使用它,规范本身的代码风格, 可是也得说一下怎么禁用eslint'
*.js *.vue 通常咱们就写这两部分,这一会儿全忽略了
由于eslint有个莫名其妙的要求,代码最后一行要求是空行,能够经过下面的方法三取消掉
rules:{ ... // 添加 'indent':0 }
在差分组件的时候,本着多个组件共享的数据放在根组件的原则, 因而咱们把共用的数据放在根组件,于此同时操做这些数据的方法也被咱们定义在根组件,子组件想要使用这些数据,想要操做这些数组怎么办呢? 想下面那样,进行组件之间的数据传递
使用:强制数据绑定的方法, ChildTarget是咱们在components模块将子组件映射得来的子组件标签, name能够是vue中data的方法,也能够是方法
<template> <ChildTarget :name="name"/> </template>
export default{ props:['name','name2'] }
@click
最经常使用的就是使用@click="方法名"
, 或者@click="value = !value"
或者@click="value = true
若是咱们向上面那样, 把公共的数据放在父组件中, 那么事件的触发必定是发生在子组件中, 子组件通常经过@click
给模板中的元素绑定上指定的动做,进而调用父组件的传递进来的方法,操做父组件传递进来的值
此外,在全部的组件中,vue的data部分都向下面这样写,是规定
data(){ return{ name:'' } }
watch:{ 监视的data中的对象 name:{ deep:true, // 深度监视 handler: function(value){ // value就是变化后的新的值 // todo } } }
从缓存中把去出来的字符串转换成json串
JSON.parse(window.localStorage.getItem('')||'默认值');
把对象,存储进浏览器的缓存
window.localStorage.setItem('自定义的key',JSON.stringfy(value))
像上面那样,若是不存在父子组件的关系,父组件不引入子组件,也就没办法把他映射成标签, 既然映射不成标签也就无法像上面那样,经过 : 冒号 强制进行数据的绑定达到传递值的效果,因而有了消息订阅
组件之间的通讯方式: 发布/订阅
绑定监听: 订阅事件
触发事件: 发布事件
借助插件-public.js
安装命令:
npm install --save pubsub-js
场景: 咱们给模板上的按钮绑定点击事件,一旦被点解他就发布事件
import PubSub from 'public-js'
使用:消息的发布
<button @click="search">Search</botton> export default{ methods:{ search(name){ // search是方法名 // name 是携带的参数,没参数就不用写 Publish.publish('search',name) } } }
消息的订阅:
mounted: { PubSub.subscribe("search",(name)=>{ // todo with name });
安装插件axios
npm install axios --save
import axios from 'axios'
发送一个get请求
axios.get(url) .then(res=>{ // todo with res }) .catch(error){ // todo }
vue是如何作到使后端乖乖交出view层的控制权的?,难道是直接使用window.location.href = url吗?
其实学过路由才知道, 使用的是vue-router,一个官方提供的路由框架,可使用我经过组合组件来组成应用程序,仰仗它的路由插件vue-router,咱们轻松控制页面的切换
咱们要作的就是将组件components映射到routers,而后告诉vue-router到哪里去渲染他们
安装插件
npm install vue-router --save
编码,其实你们都会把关于路由的编码单独放到一个叫router的文件夹中,并且,它的编码基本上是机械化的编码,分为以下几步
注意点 下面的配置部分, routes 不写乱写!!!
import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) import Home from './Home.vue' import About from './About.vue' import Me from './Me.vue' export default new VueRouter({ // 添加路由 routes:[ { path:'/home', component:Home, meta:{ // 添加自定义的字段,能够当成flag,也能够文本 } }, { path:'/about', component:About, meta:{ // 添加自定义的字段,能够当成flag,也能够文本 }, childred:[ // 嵌套路由 { path:'/about', component:About, meta:{ // 添加自定义的字段,能够当成flag,也能够文本 } } ] } }, { path:'', // 默认访问空的话,重定向到/home redirect:'/home' } ] })
原来进行页面的跳转咱们一般使用a标签,(通常把a标签设计成按钮,或者导航栏的样子,点击发送请求,进而跳转页面了), 而vue的路由其实和a标签差很少,咱们使用vue的 router-link标签替换a标签
<router-link to:'/about' class="可让我看起来像按钮的css样式"> </router-link> <router-link to:'/home' class="可让我看起来像按钮的css样式"> </router-link> <router-view ></router-view>
这样用户点击 router-link,就会把相应的子组件移植到
补充:
属性 | 类型 | 含义 |
---|---|---|
to | string | Location | 表示目标路由的连接。当被点击后,内部会马上把 to 的值传到 router.push() ,因此这个值能够是一个字符串或者是描述目标位置的对象。 |
replace | boolean | 设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push() ,因而导航后不会留下 history 记录。 |
append | boolean | 设置 append 属性后,则在当前(相对)路径前添加基路径。例如,咱们从 /a 导航到一个相对路径 b ,若是没有配置 append ,则路径为 /b ,若是配了,则为 /a/b |
咱们能够在按钮上添加下面的动做,是路由回退一级
<button @click="$router.back()"></button>
使用以下标签包裹咱们的router-view,这样当咱们再回退到上一个路由时,用户加进去的状态依然存在
<keep-alive> <router-view ></router-view> </keep-alive>
$router是路由器对象,说白了就是用它去跳转页面,美其名曰:编程式路由导航
$route是路由对象,说白了就是某一个路由对象,既然是某一个,就不能进行页面的跳转,相反是能够获取出当前路由组件的属性,它的结构图以下:
$route的组成图
需求: 咱们想发送这样的请求 http:localhost:8080/home/1/羊肉串,在路径上携带着参数1
路由怎么接收参数呢?--> 使用:占位
export default new VueRouter({ // 添加路由 routes:[ { path:'/home/:id/:type', // 若是想在路径上传递值进来,就使用:占位 component:Home, meta:{ // 添加自定义的字段,能够当成flag,也能够文本 flag:true } },
当咱们添加了/:以后,它的组成结构就变成了这个样子
像下面这样传递值进去,发起请求
<router-link to:`/home/${id}/${type}` class="可让我看起来像按钮的css样式"> </router-link>
同时,咱们也能够向下面这样使用$route. 在对应不一样的路由组件中,把里面的属性取出来, 注意啊,这样取值,前提是咱们前面使用 /:id占位,而且也整整传递值进去了
<h1>id= {{$route.params.id}}</h1>
使用<router-view >
标签传递值
<router-view msg='abc'></router-view>
在路由组件中经过props取出值,而后能够直接使用
export default{ props:[ msg:String ] }
编程式的路由导航说白了就是,不用router-link标签转而使用代码路由的跳转呗, 举个例子,咱们使用手机qq,最下面有几个导航栏,点击不一样的按钮转换到不一样的页面去,若是用编程式的路由导航就很好作
vue提供了两种编程式的路由导航实现
this.$router.replace(`/home/${id}`)
this.$router.push(`/home/${id}`)
它是个和 rout-view 和像的标签,都是用来占位的,它能够接受父组件传递给他的一段html
举个例子: 有四张路由组件,他们共用一个叫header的组件看成本身的头部, 可是他们须要传递进去属于本身的不一样的值, 下面使用slot实现
在 MyHeader.vue中
<!--首页头部--> <header class="header"> <!-- 这里使用插槽占位--> <slot name="left"></slot> <span"> <span >我是header</span> </span> <!-- 这里使用插槽占位--> <slot name="right"></slot> </header>
在父组件中使用:注意啊,下面的组件想往MyHeader.vue中的插槽中,传递进去代码片断,前提是他要把MyHeader.vue映射成标签,成为他的父组件
<div> <MyHeader> <span class="header_search" slot="left"> <i class="iconfont icon-sousuo"></i> /*在插槽的左边植入一个icon*/ </span> <!-- 给右边的插槽传递模板 --> <span class="header_login" slot="right"> <a href="" >登陆|注册</a> /* 在插槽的右边植入一个连接 */ </span> </MyHeader> </div>
官方的解释: vuex是专门为Vue.js应用程序开发的状态管理模式,它采用集中式的储存应用中全部组件的状态,并以相应的规则保证状态以一种可预期的方式发生变化
说白了: 当咱们划分组件以后,每个组件都有本身的属性,可是不一样的组件的数据是不能共享的,因而咱们可使用从父组件往子组件传播数据的模式, 并且彻底不相干的两个组件可能须要对方data里的数据,又怎么传递呢? vuex 就应对 迎战这个问题
vuex就是一个单独存储的区域,用于存放公共的属性
npm install --save vuex
建立vuex的四个组件对象,如上图
状态对象,存放一系列的状态,其实就是把子组件中data里面的字段赋复制过来
state.js文件 export default { arr: [] }
超级重要的组件, 在这个组件中咱们能够提交异步事件, 最经常使用的就是用户直接经过$store.dispatch('action中的方法名'), action会触发 mutation的调用, 间接更新状态
action.js // add方法的方法第一个参数是不变的{commit}, 其实他就是 $store 对象 // 经过这个commit方法, 把数据包装成对象传递给 mutations // 第二个参数的可选的,能够是调用者传递进来的参数,也能够是state对象 export default { add({commit},item){ // 提交mutation请求 commit(ADD_TODO,{item}); // 把数据包装成对象传递给 mutations },
真正的去执行action传进来,更新state中数据的操做
mutations.js export default { add(state,{item}){ state.arr.unshift(item); } }
包含了全部的基于state的 get计算属性, 这一点也很好用,他是一种双向的数据绑定
getters.js export default { // 计算属性 totalCount (state) { return state.arr.length }, }
编码实现: store.js
store.js import Vue from 'vue' import Vuex from 'vuex' import state from './state' import actions from './actions' import mutations from './mutations' import getters from './getter2' Vue.use(Vuex) // 对外暴露你匿名 store对象 export default new Vuex.Store({ state, actions, mutations, getters }) 把store对象,注册进main.js
作好了上面的配置,在任何地方都能用下面的方式获取出store里面的数据
this.$store.state.属性
添加上前缀,再使用
this.$store.commit('matations中的方法名','可选的参数') // 注意哦, action中是能够提交异步函数的 this.$store.dispach('action中的方法名','可选的参数')
也能够像下面这样,先进行映射就能够再也不添加任何前缀,直接使用他们
// 从vuex中引入映射 import {mapState,mapGetters,mapActions} from 'vuex' export default { computed:{ ...mapState(['state中的属性值']) ...mapGetters(['getters.js中的方法名']) }, methods:{ ...mapActions(['actions.js中的方法名']) } }