使用 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(window.localStorage.getItem('')||'默认值');

把对象,存储进浏览器的缓存

window.localStorage.setItem('自定义的key',JSON.stringfy(value))

消息订阅,打破父子组件信息传递的约束

像上面那样,如果不存在父子组件的关系,父组件不引入子组件,也就没办法把他映射成标签, 既然映射不成标签也就没法像上面那样,通过 : 冒号 强制进行数据的绑定达到传递值的效果,于是有了消息订阅

组件之间的通信方式: 发布/订阅

绑定监听: 订阅事件

触发事件: 发布事件

借助插件-pubsub.js

安装命令:

npm install --save pubsub-js

场景: 我们给模板上的按钮绑定点击事件,一旦被点解他就发布事件

  • 在使用前需要导入PubSub对象
import PubSub from 'pubsub-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层的控制权的?,难道是直接使用window.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 表示目标路由的链接。当被点击后,内部会立刻把 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

$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对象

  1. 在src下创建store文件夹,在改文件夹下创建store.js
  2. 导入Vue , Vuex
  3. 声明Vue使用Vuex
  4. 将上面的四个组件注册进来store.js

    state: 状态对象,存放的是需要共享数据的字段

    actions: 包含多个事件回调函数的对象

    mutations: 包含真正去更新state中字段的函数

    getter: 计算属性的方法
  5. 对外暴露匿名store对象
  6. 将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中的方法名'])
}
}

后端小白的VUE入门笔记, 进阶篇的更多相关文章

  1. 后端小白的VUE入门笔记, 前端高能慎入

    因为项目需要前后端分离,后端竟然不用控制view层了,页面的跳转后端不再干涉,(前端的vue经过打包后成了一张index.html) 后端只需要响应给前端json串就ok,其实这不是爽歪歪?但是觉得还 ...

  2. Vue学习笔记进阶篇——Render函数

    基础 Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template ...

  3. PHP学习笔记 - 进阶篇(11)

    PHP学习笔记 - 进阶篇(11) 数据库操作 PHP支持哪些数据库 PHP通过安装相应的扩展来实现数据库操作,现代应用程序的设计离不开数据库的应用,当前主流的数据库有MsSQL,MySQL,Syba ...

  4. PHP学习笔记 - 进阶篇(10)

    PHP学习笔记 - 进阶篇(10) 异常处理 抛出一个异常 从PHP5开始,PHP支持异常处理,异常处理是面向对象一个重要特性,PHP代码中的异常通过throw抛出,异常抛出之后,后面的代码将不会再被 ...

  5. PHP学习笔记 - 进阶篇(9)

    PHP学习笔记 - 进阶篇(9) 图形图像操作 GD库简介 GD指的是Graphic Device,PHP的GD库是用来处理图形的扩展库,通过GD库提供的一系列API,可以对图像进行处理或者直接生成新 ...

  6. PHP学习笔记 - 进阶篇(8)

    PHP学习笔记 - 进阶篇(8) 日期与时间 取得当前的Unix时间戳 UNIX 时间戳(英文叫做:timestamp)是 PHP 中关于时间与日期的一个很重要的概念,它表示从 1970年1月1日 0 ...

  7. PHP学习笔记 - 进阶篇(7)

    PHP学习笔记 - 进阶篇(7) 文件操作 读取文件内容 PHP具有丰富的文件操作函数,最简单的读取文件的函数为file_get_contents,可以将整个文件全部读取到一个字符串中. $conte ...

  8. PHP学习笔记 - 进阶篇(6)

    PHP学习笔记- 进阶篇(6) 会话控制(session与cookie) 当前的Cookie为: cookie简介 Cookie是存储在客户端浏览器中的数据,我们通过Cookie来跟踪与存储用户数据. ...

  9. PHP学习笔记 - 进阶篇(4)

    PHP学习笔记 - 进阶篇(4) 字符串操作 字符串介绍 PHP开发中,我们遇到最多的可能就是字符串. 字符串变量用于包含字符串的值. 一个字符串 通过下面的3种方法来定义: 1.单引号 2.双引号 ...

随机推荐

  1. 常用的URL Scheme

    系统 短信 sms:// app store itms-apps:// 电话 tel:// 备忘录 mobilenotes:// 设置 prefs:root=SETTING E-Mail MESSAG ...

  2. C#实体是什么

    实体 一般是指三层结构的数据库访问形式中,用于映射数据表或视图中一条记录的类的实例.例如现有数据表A 内涵 ID int(4) Info(nvarchar 50)两个字段,而有其对应的类 public ...

  3. 剑指offer第二版-3.数组中重复的数

    面试题3:数组中重复的数 题目要求: 在一个长度为n的数组中,所有数字的取值范围都在[0,n-1],但不知道有几个数字重复或重复几次,找出其中任意一个重复的数字. 解法比较: /** * Copyri ...

  4. Spring Boot 2.x (十八):邮件服务一文打尽

    前景介绍 在日常的工作中,我们经常会用到邮件服务,比如发送验证码,找回密码确认,注册时邮件验证等,所以今天在这里进行邮件服务的一些操作. 大致思路 我们要做的其实就是把Java程序作为一个客户端,然后 ...

  5. winapi创建不能改变大小的窗口

    HWND hWnd = CreateWindow( "myWindowClass", //窗口类的名字 "my first window", //窗口标题 // ...

  6. 个人永久性免费-Excel催化剂功能第18波-在Excel上也能玩上词云图

    这年头数据可视化日新月异,在Excel上做数据分析,最后一步,难免要搞个图表输出高大上一回,微软也深知此道,在Excel2016上更新了一大波图表功能,市场上很耀眼的词云图还是没加进来,虽然在各大的在 ...

  7. InstantiationException:mybatis.spring.transaction.SpringManagedTransactionFactory

    问题表现 Error creating bean with name 'sqlSessionFactory' Invocation of init method failed; nested exce ...

  8. C语言入门2-程序设计的灵魂—算法及Raptor的应用

    一.     什么是算法(5个特性) 算法就是   解决问题的方法和步骤. 算法为解决一个具体问题而采取的确定的  有限的 执行步骤  ,仅指  计算机   能执行的算法. 算法是程序设计的灵魂和核心 ...

  9. C#3.0新增功能10 表达式树 04 执行表达式

    连载目录    [已更新最新开发文章,点击查看详细] 表达式树 是表示一些代码的数据结构. 它不是已编译且可执行的代码. 如果想要执行由表达式树表示的 .NET 代码,则必须将其转换为可执行的 IL ...

  10. dll附加依赖项查看——dumpbin 命令

    VS自带工具 查看程序或动态链接库需要的动态链接库 dumpbin /dependents d:\test.exe 查看动态链接库的输出函数 dumpbin /exports d:\libmysql. ...