使用 vue-cli( 脚手架) 搭建项目
基于 vue-cli 创建一个模板项目
通过 NPM root -g 可以查看 vue 全局安装目录, 进而知道自己有没有安装 vue-cli
如果没有安装的话, 使用如下命令全局安装
cnpm install -g vue-cli
创建一个基于 webpack 的新项目, 在这过程中, 会安装依赖
vue init webpack 项目名
启动
- cd vue-router-demo
- NPM start
常用的目录结构
如果我们的项目是通过脚手架搭建的, 这已经是一个比较完善的种子项目了
|-- 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
可以在 config/index.JS 中做一下的常用配置
添加跨域的配置
配置项目的主机名, 端口号
配置是否打开浏览器
代码检查工具 eslint
在开发的时候我们主要还是关注 src 文件, 后来需要的路由, store,ajaxApi, 以及其他组件全部在创建在这个文件夹下
- 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,
入口 JS 文件 main.JS 的主要作用
创建 vue 实例, 关联 index.HTML 中 id 为 App 的 div 代码块
添加项目中的路由模块 router
添加 store 模块 ---vuex
一般做好这不配置之后 main 就不用再改动了
- 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 }
- })
根组件 App.vue
其实每一个组件都可以完整的拥有下面三部分, 当然如果哪个组件中不需要添加 CSS 样式, 可以把最后一个 style 或者 script 标签去掉
- <template>
- <div>
- <!-- 这里存放 -->
- </div>
- </template>
- <//script>
- export default {
- name: 'app'
- }
- <///script>
- <style>
- </style>
组件间的相互调用
比如根组件想使用 hello.vue 组件, 怎么做呢?
像下面这样, 三步走
第一步: 引入组件
第二步: 将组件映射成 target 标签
第三步使用标签
- <template>
- <div>
- <!-- 第三步使用标签 -->
- <hello/>
- <div/>
- <template/>
- <script>
- import hello form './XXX/hello.vue'
- export default{
- // 将组件映射成标签
- components:{
- hello
- }
- }
- <style>
- </style>
第二步中引入标签时也可以去掉. vue 后缀
或者直接这样写, 是从 @/ 代表的是 src/
import hello form '@/XXX/hello'
打包与发布
打包
打包的命令:
NPM run build
项目经过打包, 产出是一个 dist 文件, 里面分别是 index.HTML 和 静态资源文件夹, 这也是前后端分离开发的特色, 后端想控制 view 层, 也难了, 只有一张 index.HTML
发布方法 1 - 静态服务器工具包
命令:
- NPM install -g serve // 安装工具
- serve dist
发布方法 2 - 使用 tomcat 服务器
注意点, 使用 tomcat 当服务器, 要求文件夹的名字和项目的名字要一样, 修改的步骤如下:
修改
/build/webpack_prod.conf.JS
文件
- output:{
- ...
- pathPath:'项目名称'
- }
编译重新打包
NPM run build
把打包得到的 dist 文件夹改名, 改成项目名
将改名完事后的文件拷贝到 tomcat 的 webapps 目录下, 运行 tomcat
eslint 的编码规范检查
好的习惯就是使用它, 规范自己的代码风格, 但是也得说一下怎么禁用 eslint'
方法一: 通过如果是 webstorm 编译器的话, 点击 file/settings/ , 搜索 eslint, 可以 enable 掉
方法二: 编辑. eslintignore 文件, 添加自己想被忽略的文件
*.JS
*.vue
一般我们就写这两部分, 这一下子全忽略了
因为 eslint 有个莫名其妙的要求, 代码最后一行要求是空行, 可以通过下面的方法三取消掉
方法三: 编辑. eslintrc.JS
- 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 模块
watch:{
监视的 data 中的对象
- name:{
- deep:true, // 深度监视
- handler: function(value){ // value 就是变化后的新的值
- // todo
- }
- }
- }
缓存模块
从缓存中把去出来的字符串转换成 JSON 串
JSON.parse(Windows.localStorage.getItem('')||'默认值');
把对象, 存储进浏览器的缓存
Windows.localStorage.setItem('自定义的 key',JSON.stringfy(value))
消息订阅, 打破父子组件信息传递的约束
像上面那样, 如果不存在父子组件的关系, 父组件不引入子组件, 也就没办法把他映射成标签, 既然映射不成标签也就没法像上面那样, 通过 : 冒号 强制进行数据的绑定达到传递值的效果, 于是有了消息订阅
组件之间的通信方式: 发布 / 订阅
绑定监听: 订阅事件
触发事件: 发布事件
借助插件 - public.JS
安装命令:
NPM install --save pubsub-JS
场景: 我们给模板上的按钮绑定点击事件, 一旦被点解他就发布事件
在使用前需要导入 PubSub 对象
import PubSub from 'public-js'
使用: 消息的发布
- <button @click="search">Search</botton>
- export default{
- methods:{
- search(name){
- // search 是方法名
- // name 是携带的参数, 没参数就不用写
- Publish.publish('search',name)
- }
- }
- }
消息的订阅:
依然是第一步: 引入 PubSub 对象
编码实现:
- 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 层的控制权的?, 难道是直接使用 Windows.location.href = url 吗?
其实学过路由才知道, 使用的是 vue-router, 一个官方提供的路由框架, 可以使用我通过组合组件来组成应用程序, 仰仗它的路由插件 vue-router, 我们轻松控制页面的切换
我们要做的就是将组件 components 映射到 routers, 然后告诉 vue-router 到哪里去渲染他们
定义路由器
安装插件
NPM install vue-router --save
编码, 其实大家都会把关于路由的编码单独放到一个叫 router 的文件夹中, 而且, 它的编码基本上是机械化的编码, 分为如下几步
引入 Vue,VueRouter
声明 Vue.use(VueRouter)
引入路由组件
对外暴露路由器对象, 并且把路由组件配置进路由器对象
注意点 下面的配置部分, 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 | 表示目标路由的链接。当被点击后,内部会立刻把 & nbsp;to 的值传到 & nbsp;router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。 |
replace | boolean | 设置 & nbsp;replace 属性的话,当点击时,会调用 & nbsp;router.replace() 而不是 & nbsp;router.push(),于是导航后不会留下 history 记录。 |
append | boolean | 设置 & nbsp;append 属性后,则在当前(相对)路径前添加基路径。例如,我们从 & nbsp;/a 导航到一个相对路径 & nbsp;b,如果没有配置 & nbsp;append,则路径为 & nbsp;/b,如果配了,则为 & nbsp;/a/b |
回退到上一个路由
我们可以在按钮上添加下面的动作, 是路由回退一级
<button @click="$router.back()"></button>
缓存路由组件
使用如下标签包裹我们的 router-view, 这样当我们再回退到上一个路由时, 用户加进去的状态依然存在
- <keep-alive>
- <router-view></router-view>
- </keep-alive>
$router 与 $route
$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}`)
slot 标签
它是个和 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
官方的解释: vuex 是专门为 vue.js 应用程序开发的状态管理模式, 它采用集中式的储存应用中所有组件的状态, 并以相应的规则保证状态以一种可预期的方式发生变化
说白了: 当我们划分组件之后, 每一个组件都有自己的属性, 但是不同的组件的数据是不能共享的, 于是我们可以使用从父组件往子组件传播数据的模式, 而且完全不相干的两个组件可能需要对方 data 里的数据, 又怎么传递呢? vuex 就应对 迎战这个问题
vuex 就是一个单独存储的区域, 用于存放公共的属性
安装命令:
NPM install --save vuex
创建 vuex 的四个组件对象, 如上图
vuex 的组件对象一: state.JS
状态对象, 存放一系列的状态, 其实就是把子组件中 data 里面的字段赋复制过来
state.JS 文件
- export default {
- arr: []
- }
vuex 的组件对象二: actions.JS
超级重要的组件, 在这个组件中我们可以提交异步事件, 最常用的就是用户直接通过 $store.dispatch('action 中的方法名'), action 会触发 mutation 的调用, 间接更新状态
action.JS
- // add 方法的方法第一个参数是不变的 {commit}, 其实他就是 $store 对象
- // 通过这个 commit 方法, 把数据包装成对象传递给 mutations
- // 第二个参数的可选的, 可以是调用者传递进来的参数, 也可以是 state 对象
- export default {
- add({commit},item){
- // 提交 mutation 请求
- commit(ADD_TODO,{item}); // 把数据包装成对象传递给 mutations
- },
vuex 的组件对象三: mutations.JS
真正的去执行 action 传进来, 更新 state 中数据的操作
mutations.JS
- export default {
- add(state,{item}){
- state.arr.unshift(item);
- }
- }
vuex 的组件对象四: getters.JS
包含了所有的基于 state 的 get 计算属性, 这一点也很好用, 他是一种双向的数据绑定
getters.JS
- export default {
- // 计算属性
- totalCount (state) {
- return state.arr.length
- },
- }
把四个组件拼装成 store 对象
在 src 下创建 store 文件夹, 在改文件夹下创建 store.JS
导入 Vue , Vuex
声明 Vue 使用 Vuex
将上面的四个组件注册进来 store.JS
state: 状态对象, 存放的是需要共享数据的字段
actions: 包含多个事件回调函数的对象
mutations: 包含真正去更新 state 中字段的函数
getter: 计算属性的方法
对外暴露匿名 store 对象
将 store 配置进 main.JS vue 的入口 JS 中
编码实现: 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
更全面的数据处理流程图
获取 state 中的值
做好了上面的配置, 在任何地方都能用下面的方式获取出 store 里面的数据
this.$store.state. 属性
使用 vuex, 改变状态值
添加上前缀, 再使用
- 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 中的方法名'])
- }
- }
来源: https://www.cnblogs.com/ZhuChangwu/p/11325489.html