文章目录
Vue组件化编码
- 使用
vue-cli
创建模板项目,它是官方提供的脚手架工具。 - 脚手架的作用:从https://github.com/vuejs-templates下载模板项目
创建vue项目
//全局安装脚手架。安装成功后就会多个一个命令 vue
npm install vue-cli -g
//其中模板名称可以为:webpack、pwa、webpack-simple、simple、browserify、browserify-simple
//vue init 模板名称 项目名称
vue init webpack vue_demon
//初始化项目后,会自动提示创建项目的package.json文件的相关信息,最后还会提示是否是npm下载、yarn下载、自己下载,这里选的是自己下载。此时需要切换至项目所在目录
cd vue_demon
npm install
//开发环境下运行
npm run dev
//访问 http://localhost:8080
基于脚手架编写项目
什么是组件??
- 一个局部的功能界面,这个局部功能界面的相关的所有资源(比如:html、js、css、img)都是组件的一个组成部分
- 一个功能模块,一个界面的局部功能模块
组件的组成部分?
- 属性
- 自定义属性:组件中props中声明的属性
- 原生属性:没有声明的属性,默认挂载到组件的根元素上,设置为inheritAttrs为false可以关闭自动挂载
- 特殊属性class、style:挂载到组件的根元素上,支持字符串、对象、数组等多种语法
- 事件
- 普通事件
- 修饰符事件
- 插槽
- 普通插槽
- 作用域插槽
文件描述
main.js
入口文件:
创建vue对象
将App组件映射为标签
通过模板将App标签进行显示
import Vue from 'vue' import App from './App.vue' const vm = new Vue({ el: '#app', components: {App}, template: '<App/>' }) Vue.use(vm)
App.vue
根组件
在根组件中引入HelloWord.vue组件
- 在
<script>
标签中引入组件 - 映射组件标签
- 使用组件标签
【HelloWord.vue】组件
//vue文件的模板
<template>
//html
<div>
//必须要有根标签
</div>
</template>
<script>
//js
export default{ //配置对象,和vue对象的配置对象一致
}
</script>
<style>
//样式
</style>
vue的配置对象里面的data可以是对象,也可以是函数。
在组件中配置对象中的data必须是函数
即
<script> //js export default{ //配置对象,和vue对象的配置对象一致 data(){ return { msg:'hello vue' } }, computed: { ... }, methods: { ... } } </script>
components文件夹
存放一些其他的组件
项目的打包与发布
打包:在当前文件下编译打包,并生成dist文件夹
npm run build
发布:
【方法一】:使用静态服务器工具包
npm install -g serve //全局安装serve
serve dist
//访问 http://localhost:5000
【方法二】:使用动态web服务器(tomcat)
-
修改配置 webpack.prod.conf.js
output:{ publicPath:'/vue_demon/' //打包文件夹的名称(即准备发布的项目名称)假设为vue_demon }
-
重新打包:
npm run build
-
修改dist文件夹为项目名vue_demon
-
将vue_demon拷贝到运行的tomcat的webapps目录下
eslint
是一个代码规范的检查工具
【如何让一个规则失效??】
查找.eslintrc.js
文件中修改:找到rules
...
rules:[
//'规则名':'off' 或者 0
'indent': 'off'
]
...
因为修改了配置,因此需要重启服务器:npm run dev
【方法二】:在.eslintignore
文件中添加需要忽视检查的文件后缀名
/build/
/config/
/dist/
/*.js
*.js
*.vue
todos练习
【注意事项】:
在父组件给子组件传递数据时,子组件在接收时需要进行声明(类型、是否必须、默认值等);声明之后此数据就会成为该组件的属性,可以在模板中直接读取它
通常情况下:数据在哪里,操作数据的方法就定义在哪里
初始化显示数据
【main.js】
import Vue from 'vue'
import App from './App.vue'
const vm = new Vue({
el: '#app',
// 将App映射为标签
components: {App},
// 将App标签添加到模板字符串中
template: '<App/>'
})
Vue.use(vm)
【App.js】
<template>
</template>
<script>
import TodoHeader from './components/TodoHeader'
import TodoList from './components/TodoList'
import TodoFooter from './components/TodoFooter'
export default {
components: {
TodoHeader,
TodoList,
TodoFooter
},
data () {
return {
...
}
},
methods: {...}
}
</script>
<style>
</style>
【其他组件】
<template>
....
</template>
<script>
export default {
props: {
addTodo: Function
},
data () {
return {
...
}
},
methods: {
...
}
}
</script>
<style lang="css">
</style>
localstorage存储数据
【基本概念】
- cookie:主要用于保存登录信息
- sessionStorage:会话,是可以将一部分数据在当前会话中保存下来,刷新页面数据依旧存在。但是页面关闭后,sessionStorage中的数据就会被清空。
- localStorage:是HTML5标准中新加入的技术,当然早在IE6时代就有一个userData的东西用于本地存储,而当时考虑到浏览器的兼容性,更通用的方案是使用flash。如今localStorage被大多数浏览器所支持。
【三者区别】
-
存储大小
cookie:一般不超过4K(因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识)
sessionStorage:5M或者更大
localStorage:5M或者更大
-
数据有效期
cookie:一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,若设置了时间,cookie就会存放在硬盘里,过期才失效
sessionStorage:仅在当前浏览器窗口关闭之前有效,关闭页面或者浏览器会被清除
localStorage:永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久清除,因此用作持久数据
-
作用域
cookie:在所有同源窗口中都是共享的
sessionStorage:在同一个浏览器窗口是共享的(不同浏览器、同一个页面也是不共享的)
localStorage:在所有同源窗口中都是共享的
-
通信
ccokie:十种携带在同源的http请求中,即使不需要,故cookie在浏览器和服务器之间来回传递;如果使用cookie保存过多数据会造成性能问题
sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信;不会自动把数据发送给服务器,仅在本地保存
localStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信;不会自动把数据发送给服务器,仅在本地保存
-
易用性
cookie:需要自己进行封装,原生的cookie接口不够友好
sessionStorage:原生接口可以接受,可以封装来对Object和Array有更好的支持
localStorage:原生接口可以接受,可以封装来对Object和Array有更好的支持
【应用场景】
- cookie:判断用户是否登录过网站,以便实现下次自动登录或记住密码;保存事件信息等
- sessionStorage:敏感账号一次性登录;单页面用的较多(sessionStorage 可以保证打开页面时 sessionStorage 的数据为空)
- localStorage:常用于长期登录(判断用户是否已登录),适合长期保存在本地的数据
【什么时候存??】 =》todosArr发生变化:添加、删除、勾选 都要进行保存
【什么时候读??】=》初始化数据
【存什么??】=》新添加进来的todoItem
export default {
saveTodos (todos) {
// 保存:由js对象转为Json字符串
window.localStorage.setItem('todos_key', JSON.stringify(todos))
},
readTodos () {
// 读取:由Json字符串转为js对象
return JSON.parse(window.localStorage.getItem('todos_key') || '[]')
}
}
组件通信
组件的通信,包括父子组件、祖孙组件、兄弟组件等
props
用于接收来自父组件的数据
【父 =》子】
【父=》子=》孙】
vue自定义事件
- 绑定监听
- 触发事件
【父=》子】
注意:这里的自定义事件主要是针对于【父子组件】之间的通信,用来代替props方式的通信方式
消息的订阅与发布
-
下载:
npm install pubsub-js --save
这个库向外提供了一个Pubsub对象
订阅消息:
Pubsub.subscribe('消息名',callback(msg,数据))
,这里的回调函数建议使用箭头函数,否则函数中的this指向就不是组件,而是暴露出来的Pubsub对象发布消息:
Pubsub.publish('消息名',数据)
-
订阅消息 ==》 绑定事件监听; 发布消息 ==》 触发事件
订阅消息属于异步操作,因此我们一开始就可以给指定的标签绑定事件监听,mounted周期函数中经常来执行一些异步代码
优点:组件之间的关系可以没有任何要求。
slot
以上的通信指得都是【数据的传递】;而slot方式用于父组件向子组件传递【标签数据】
父组件:
<div>
<TodoFooter>
<input slot="selectAll" type="checkbox" v-model="selectAll"/>
<span slot="count">已完成{{completeNum}} / 全部{{this.todos.length}}</span>
<button slot="deleteChecked" class="btn btn-danger" @click="deleteCompleted" v-show="completeNum">清除已完成任务</button>
</TodoFooter>
</div>
子组件
<div class="todo-footer">
<label>
<!-- 使用slot将页面分为三个插槽 -->
<!-- <input type="checkbox" v-model="selectAll"/> -->
<slot name="selectAll"></slot>
</label>
<span>
<!-- <span>已完成{{completeNum}} / 全部{{this.todos.length}}</span> -->
<slot name="count"></slot>
</span>
<!-- <button class="btn btn-danger" @click="deleteCompleted" v-show="completeNum">清除已完成任务</button> -->
<slot name="deleteChecked"></slot>
</div>
注意:然后通过slot将子组件中的标签插到父组件中,此时在子组件中定义的方法、数据(即被插入的标签中使用到的)也需要移动到父组件中。
vue-ajax
vue项目中常用的两个库
-
vue-resource
vue插件,非官方库,vue1.x中使用广泛
npm install vue-resource --save
-
axios
通用的ajax请求库,官方推荐v,vue2.x使用广泛
npm install axios --save
github接口:
https://api.github.com/search/repositories?q=v&sort=stars
import axios from 'axios'
axios.get(url)
.then(
response => {
// 成功回调
...
},
response => {
// 失败回调
...
}
)
})
vue UI组件库
【常用的UI组件库】
-
Mint UI
主页:
http://mint-ui.github.io/#!/zh-cn
说明:饿了么开源的基于vue的移动端UI组件库
-
Elment
主页:
https://element.eleme.cn/#/zh-CN
说明:饿了么开源的基于vue的pc端UI组件库
【这里列举MintUI来进行说明,这里项目是vue-cli脚手架搭建】
-
下载
npm i mint-ui -S
-
在项目中引入MintUI(这里只是列举了【按需引入】)
按需引入需要借助第三方插件:
npm install babel-plugin-component -D
修改项目中的
.babelrc
文件: 在
plugins
数组中添加:["component", [ { "libraryName": "mint-ui", // 样式自动打包,我们无需在动手 "style": true } ] ]
-
使用
因为是在移动端使用,因此以移动优先的原则,配置【视口】和【事件延迟】
//视口配置 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> // 处理事件延迟 <script> if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } if(!window.Promise) { document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>'); } </script>
-
按需引入标签
import { Button, Cell } from 'mint-ui' // 注册成标签(全局) Vue.component(Button.name, Button) Vue.component(Cell.name, Cell) /* 或写为 * Vue.use(Button) * Vue.use(Cell) */ //从语法上也可以写成如下,但是语义不好 Vue.component('xxx', Button) Vue.component('bbb', Cell)
vue-router
官方提供的用来实现SPA的vue插件
github:https://github.com/vuejs/vue-router
中文文档:http://router.vuejs.org/zh-cn
下载:npm install vue-router --save
路由
-
由
key:value
组成的键值对 -
key==》 path, value:则分为:
前台路由:value =》组件
后台路由:value =》处理请求的回调函数
路由器
路由器用来管理路由的
相关API说明
【注意】:
- path: ‘/about’, 其中path里面的
/
永远代表的是【根路径】path:''
,路径没有写代表的是当前文件所在路径
-
VueRouter()
用于创建路由器的构造函数new VueRouter({ //多个配置选项 /** **/ })
-
路由配置
routers:[ { //一般路由 path: '/about', component: About }, { //自动跳转路由(当请求的是根路径时,去显示的是about组件页面) path: '/', redirect:'/about' } ]
-
注册路由器
import router from './router' //import router1 from './router' new Vue({ router //完整写法 //router:router1 })
-
使用路由组件标签
<router-link>
用来生成路由链接<router-link to='/xxx'>Go to xxx</router-link>
<router-view>
用来显示当前路由组件界面<router-view></router-view>
项目文件夹说明
-components => 用来存放页面中的普通组件
-views 或者 -pages => 用来存放将要映射成路由的组件即路由组件
-router 里面一般有index.js文件用来配置路由
注册路由
注册路由
router文件夹里面 index.js ==》 路由器模块即:配置路由
/** 将路由组件和路径相匹配,即完成了正常组件==》路由组件的转换 **/ import Vue from 'vue' import VueRouter from 'vue-router' import About from '../views/about' Vue.use(VueRouter) export default new VueRouter({ //n个路由 routes: [ { //路径 path:'/about', //路由组件 component:About } ] })
嵌套路由的配置
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../views/about'
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path:'/about',
component:About,
//配置嵌套路由
children:[
{
path: '/news',
components: News
},
{
path: xxx,
components:xx
}
]
}
]
})
路由器的配置
路由器的配置:在项目的入口js文件,即main.js中配置
...
// 这里引入的就是上面的routes文件夹下的index.js文件中默认暴露的对象
// 所以也可以这样写 import routerxx from './router'(因为是默认暴露)
import router from './router'
...
new Vue({
//配置对象的属性名都是一些确定的名称,不可以随便更改
el: '#app',
components:{App},
template:'</App>',
// 当引入的名字也是router时,一般都简写为:router
router: router
})
【注意】:
import router from './router'
//等效于
//import router from './router/index.js'
这个不是vue的规定而是node加载模块的方式,当require(’./router’)(import会被转为require),node是这样的寻找目标的:
- 首先查找目录下有没有
router.js
或者router.node
,如果有就导入- 没有的话就查看是否有router目录,没有就抛出异常
Cannot find module './router
- 如果有会在router目录下找
package.json
文件,如果有则按照package.json
的配置来- 如果没有
package.json
文件,则看是否有index.js
或index.node
文件,如果有就导入,没有就失败
路由的使用
<router-link>
用来生成路由链接
<router-link to='/xxx'>Go to xxx</router-link>
<router-view>
用来显示当前路由组件界面
<router-view></router-view>
路由使用总结
路径和组件对应起来,在页面中把组件渲染出来
-
页面实现(HTML模板中),定义页面中点击 :to =" 去哪”(router-link),然后在指定显示的地方(router-view)
-
配置路由( router文件夹==》index.js)
-
定义route。一条路由两部分组成: path和component
-
两条路由,组成routes
const routes = [ { path: ‘/home’, component: Home }, { path: ‘/about’, component: About} ]
- 对路由进行管理 =》创建路由
const router = new VueRouter({ routes })
-
-
注入Vue根实例进行使用(main.js)
const app = new Vue({ router })
用户点击 router-link标签时,会去寻找to属性。它的to属性和js中配置的路径(path:’/home’, component: Home) path 对应。找到匹配的组件,最后把组件渲染到标签所在的地方
向路由组件传递数据
访问网站并登陆成功, 显示页面+名字 ==》 名字不同。user 是一个组件。不同用户【id不同】 =》同一个user组件中 =》 路由不能写死
params方式
-
创建user.vue 组件
-
router中的index.js 引入 user 组件并进行使用
{ path: '/components/user/:id', // :id 占位 component: user }
-
App.vue中与路由建立连接
<router-link to="/components/user/123">user123</router-link> // es6动态拼接数据 <router-link to="`/components/user/${user.id}`">user456</router-link>
- 获取数据
this.$route.params.id
query参数
-
配置路由
{ path: '/components/user', component: user }
-
使用路由组件
<router-link to="/components/user?id=123">user123</router-link> <router-link to="`/components/user?id=${user.id}`">user456</router-link>
-
获取数据
this.$route.query.id
router-view标签属性携带数据
标签中有props属性
要知道的我们是不可以通过路由组件来携带属性的。因为路由组件此时还不是标签,只是注册路由,因此不可以使用props
属性
组件是通过标签来显示的,路由组件router-link
是通过router-view
标签来显示的,因此我们可以使用router-view
标签的props
来传递数据
【步骤】:
-
通过
router-view
传递数据<template> <!--生成路由链接--> <router-link to="/about" class="list-group-item">About</router-link> <router-link to="/home" class="list-group-item">Home</router-link> <!--用来显示路由组件的标签--> <router-view msg="abc"></router-view> <!--此时About路由和Home路由都可以获取msg的数据--> </template>
-
获取数据(about.vue或home.vue)
<template> <h1>{{msg}}</h1> </template> <script> //声明得到的数据 props: { msg: String } </script>
缓存路由组件
【要知道的】:默认情况下,被切换的路由组件对象会死亡释放,再次回来时是重新创建的
此时如果缓存路由组件对象,就可以提高用户体验
【编码实现】:
<keep-alive>
<router-view></router-view>
</keep-alive>
编程式路由导航
this即路由组件对象中有两个特别的属性:
$route
代表当前组件:存放数据
$router
代表路由器:提供操作路由的功能方法
从A页面跳转到B页面的做法:
- 使用
a
标签 - 假如是按钮,则给按钮添加【点击监听】,通过js的方式进行页面跳转(编程式)
即编程式路由导航:通过js来显示路由之间的页面跳转
组件对象this除了有$route
属性,还有$router
属性,我们可以通过this.$router.push
和$this.router.replace
方法来实现页面的跳转
页面嵌套顺序:news => messages => messageDetail
push方法:
访问顺序:
news => messages
此时使用push 跳转到:messageDetail 页面,点击回退则会到 messages页面
replace方法:
访问顺序:
news => messages
此时使用replace方法跳转到:messageDetail页面,点击回退则会到news页面
【注意】:
$router.back()
:回退上一层
<template>
<button @click="handlePush(message.id)">push查看</button>
<button @click="handleReplace(message.id)">replace查看</button>
</template>
<script>
...
methods: {
handlePush (id) {
this.$router.push(`/home/message/detail/${id}`)
},
handleReplace (id) {
this.$router.replace(`/home/message/detail/${id}`)
}
}
...
</script>