Vue2.0
1.认识Vue
1.创始人以及发展历程
尤雨溪 (EvanYou)
美籍华人
Vue Technology LLC 创始人
高中:上海复旦大学附中
大学:纽约科尔盖特大学
发展历程
1.2014 年 2 月
尤雨溪开源了一个前端开发库 Vue.js。Vue.js 是构建 Web 界面的 JavaScript 库,也是一个通过简洁的 API 提供高效数据绑定和灵活组件的系统。
2.2016 年 9 月
在南京的 JSConf 上,尤雨溪正式宣布以技术顾问的身份加盟阿里巴巴 Weex 团队,来做 Vue 和 Weex 的 JavaScript runtime 整合,目标是让大家能用 Vue 的语法跨三端。
2020 年 4 月
Vue3.0beta版本测试发布。
2. Vue是什么?
Vue.js是一款轻量级的、以数据驱动的、前端JS框架,是一个通过简洁的API提供高效的数据绑定和灵活的组件系统。
3.与Jquery的技术比较优势在哪里
旧:Jquery
操作DOM元素
jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的
复杂页面维护成本大
jquery则需要获取dom元素节点,并对dom进行添加一个标签的操作,如果dom结构特别复杂,或者添加的元素非常复杂,则代码会变得非常复杂且阅读性低。
很难达到组件化页面
JQuery 时代的代码大部分情况下是面条代码,耦合严重
性能损耗
损耗浏览器资源
新:Vue.js
数据与视图分离
Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
数据双向绑定
这也就是vue.js最大的优点,通过MVVM思想实现数据的双向绑定,让开发者不用再操作dom对象,有更多的时间去思考业务逻辑。
灵活的组件化
Vue.js通过组件,把一个单页应用中的各种模块拆分到一个一个单独的组件中,我们只要先在父级应用中写好各种组件标签,并且在组件标签中写好要传入组件的参数,然后再分别写好各种组件的实现,然后整个应用就算做完了。
虚拟DOM,运行更快
Virtual DOM,是一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化,由于这个DOM操作属于预处理操作,并没有真实的操作DOM,所以叫做虚拟DOM
4.技术点整理
5.学习需要掌握的知识点
轻量级的框架
能够自动追踪依赖的模板表达式和计算属性,提供 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API,使读者更加容易理解,能够更快上手。
双向数据绑定
声明式渲染是数据双向绑定的主要体现,同样也是 Vue.js 的核心,它允许采用简洁的模板语法将数据声明式渲染整合进 DOM。
客户端路由
Vue-router 是 Vue.js 官方的路由插件,与 Vue.js 深度集成,用于构建单页面应用。Vue 单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来
指令
Vue.js 与页面进行交互,主要就是通过内置指令来完成的,指令的作用是当其表达式的值改变时相应地将某些行为应用到 DOM 上。
组件化
可随时引用,通过传入参数实现不同的页面,可子父引用。
状态管理
状态管理实际就是一个单向的数据流,State 驱动 View 的渲染,而用户对 View 进行操作产生 Action,使 State 产生变化,从而使 View 重新渲染,形成一个单独的组件。
2. 搭建Vue2.0项目
1. npm、cnpm node环境搭建vue脚手架
1. 安装node.js环境
1.进入官网
https://nodejs.org/en/
2.安装msi,安装目录到C盘
安装好后,使用cmd执行 node- v npm -v看看是否都输出了版本号
3.在除C盘外创建一个nodejsFile文件夹,创建两个文件夹 node_global和node_cache,然后运行以下命令
npm config set prefix "D:\Program Files\nodejs\node_global"
npm config set cache "D:\Program Files\nodejs\node_cache"
4.检查当前系统变量中,path路径有没有叫C:\ProgramFiles\nodejs\node_modules
如果有,创建一个同名路径文件夹在C盘之外的盘符,如果没有就不用管了
- 在path变量中配置你的C:\Program Files\nodejs\node_modules路径
2. 安装淘宝镜像 cnpm
功能:和npm一样,npm是从海外镜像仓库下载,cnmp 是从阿里淘宝镜像仓库下载
npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完成使用:cnpm -v 查看版本
3.安装webpack
npm install webpack -g
安装完成使用:npm webpack -v 查看版本
4. 下载vue脚手架
1.下载脚手架资源
cnpm install -g [email protected]
2.去到你的gloab目录查看是否有vue开头的文件
- 到别的文件夹下创建一个空的文件夹,在文件夹中按住shift+鼠标右键,点击在此处打开pwershell窗口
- 打开窗口输入:vue init webpack
5.初始化构建vue脚手架
6.运行vue项目
在项目根目录下按住shift+鼠标右键,点击在此处打开pwershell窗口,执行 npm run dev
3. 使用VSCode构建Vue项目
下载VsCode
https://code.visualstudio.com/
组件下载
创建vue项目
- 创建一个空的项目文件夹
- 使用vsCode打开这个文件夹
- 设置vsCode语言:ctrl+shift+P 输入指令:Display language 先选择英文重启后再选择中文再重启就好了
- 打开终端
vue init webpack
会出现错误:not promite 。。。。 vsCode终端控制台没有系统写入权限
使用本机自带的cmd窗口使用管理员权限启动
将目录跳转至项目路径再执行vue init webpack指令
5.启动项目
npm run dev
6.退出运行
ctrl+c
4. 编写第一个vue文件
<!-- Dom页面 -->
<template>
<!-- 所有的页面元素都要卸载div之内 -->
<div id='UserIndex'>
</div>
</template>
<!-- 组件js -->
<script>
export default {
name:'UserIndex',
data(){
}
}
</script>
<!-- CSS代码 -->
<style scoped>
</style>
使用VSCode创建一个自定义代码片段
文件–》首选项—》配置用户代码片段
{
"Print to console": {
"prefix": "myvue",// 代码段名称
"body": [ //代码内容
"<!-- Dom页面 -->",
"<template>",
"<div id=''>",
"",
"</div>",
"</template>",
"",
"<!-- 组件js -->",
"<script>",
"export default {",
"name:'',",
"data(){",
"",
"}",
"}",
"</script>",
"",
"<!-- CSS代码 -->",
"<style scoped>",
"",
"</style>"
],
"description": "myvue"
}
}
5.App.vue文件
作用:vue项目首页,可以编写全局项目中公共的样式
注意:一般如果项目集成了路由功能,app.vue只会写一个路由标签
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
}
</style>
6.main.js-主入口文件
作用:配置通用组件的引入、vue通用配置
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
// 创建vue,绑定主视图
// 脚手架项目中vue实例只会有一个,存在main.js中
new Vue({
el: '#app',
router,
components: {
App },
template: '<App/>'
})
vue实例
每个 Vue.js 应用都是通过构造函数 Vue 创建一个 Vue 的根实例 启动的
7. Vue组件的生命周期(vue2.0)
1. 组件创建阶段-create
- 实例化组件
- beforeCreate 创建前
- 开启数据监听
- 初始化vue内部方法
- created 创建完成
vue中使用钩子函数
<template>
<div class="hello">
123
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
}
},
//创建前的钩子
beforeCreate(){
console.dir("beforeCreate");
},
//创建后
created(){
console.dir("created");
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
2.组件渲染阶段-mount
vue选择渲染模板,是要使用vue组件的方式渲染还是只是渲染部分html
1.beforeMount - dom元素渲染之前
开始渲染
- mounted - dom挂载结束
<template>
<div class="hello">
123
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
}
},
//创建前的钩子
beforeCreate(){
console.dir("beforeCreate");
},
//创建后
created(){
console.dir("created");
},
//Dom挂载之前
beforeMount(){
console.dir("beforeMount");
},
//dom挂载完成
mounted(){
console.dir("mounted");
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
3.组件运行阶段-数据更新-update
监听器会监听所有data值的变化
1.beforUpdate - 数据更新之前
使用VDom手段动态渲染html
- updated - 数据渲染完成
<template>
<div class="hello">
{
{ name }}
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
name:"蔡徐坤"
}
},
//创建前的钩子
beforeCreate(){
console.dir("beforeCreate");
},
//创建后
created(){
console.dir("created");
},
//Dom挂载之前
beforeMount(){
console.dir("beforeMount");
},
//dom挂载完成
mounted(){
console.dir("mounted");
},
//数据更新之前
beforeUpdate(){
console.dir("beforeUpdate");
},
//数据更新完成
updated(){
console.dir("updated");
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
4.组件销毁阶段-destroy
注意:组件默认情况下不会主动销毁,需要借助v-if指令或者,Vue.$destroy()才会触发vue的销毁流程
- 组件是否进入销毁流程(v-if指令或者,Vue.$destroy())
- beforeDestroy - 销毁之前
- 进行销毁 - 组件中所有的data值缓存都会消失、vdom缓存也会清除
- destroyed - 销毁结束
8.main.js进行全局配置
#取消 Vue 所有的日志与警告 - 开发不要配,生产环境配
Vue.config.silent = true
#配置是否允许 vue-devtools 检查代码 - 开发不要配,生产环境配
Vue.config.devtools = true
#指定组件的渲染和观察期间未捕获错误的处理函数-全局异常处理回调
Vue.config.errorHandler = function (err, vm, info){
}
#设置为 false 以阻止 vue 在启动时生成生产提示 - 开发不要配true,生产环境配
Vue.config.productionTip = false
9. Vue语法
1. 插值表达式-文本类型(数值、boolean、字符串、字符、对象中的文本类型)
语法:{ { 数据变量名称 }}
是将vue绑定的数据渲染到视图产生关联,实现双向绑定
<template>
<div class="hello">
<h1>大家好我叫:{
{ name }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
name:"蔡徐坤456"
}
}
}
</script>
v-once指令
编写位置:插值表达式存在的开始标签中
作用:让插值表达式里的值不会根据data的变化而渲染,永远保持第一次加载的值
<template>
<div class="hello">
<h2>{
{ name }}</h2>// 蔡徐坤123
<h2 v-once>大家好我叫:{
{ name }}</h2> // 蔡徐坤
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
name:"蔡徐坤" // 蔡徐坤123
}
}
}
</script>
2.动态插入HTML文本
注意:{ { XXX }}解析的过程只会按照纯文本方式解析,如果要解析html代码段加载到dom中,需要使用v-html指令
v-html指令
<template>
<div class="hello">
<!-- 加载html是以纯文本的方式加载 -->
<!-- <h2>{
{ person.myhtml }}</h2> -->
<!-- 将person.myhtml中的html代码加载到当前标签的子标签中 -->
<h2 v-html="person.myhtml"></h2> // XXX.html("xxx")
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
name:"蔡徐坤",
myhtml:"<span>123</span>"
}
}
}
}
</script>
3.标签属性值动态绑定(重点经常使用)
注意:title={ { xxxx }}不行,插值表达式不能使用在属性值以及属性名称上,标签位置上都不能使用插值表达式
那如果需要动态绑定一个数据给标签的属性值怎么办?就要使用v-bind指令
v-bind指令
<template>
<div class="hello">
<h1 v-bind:title="person.title" >欢迎访问网站</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
name:"蔡徐坤",
title:"点击给我充值50块!"
}
}
}
}
</script>
v-bind指令可以简写为":"
<h1 :title="person.title" >欢迎访问网站</h1>
4.动态绑定表达式
当点击时动态绑定一段js代码
借助v-bind来实现
<template>
<div class="hello">
<h1 :οnclick="person.text" >欢迎访问网站</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
//表达式字符串
text:"javascript:var c=0;alert(c)"
}
}
}
}
</script>
5.vue指令
编写的位置:开始标签中在标签的属性位置编写
1. v-once(不可再更新)
2.v-bind(动态绑定属性值)
3.v-html(动态添加子元素解析html)
4.v-on(事件绑定)
复杂写法:
<template>
<div class="hello">
<!-- 点击h1标签跳转到百度首页 -->
<h1 v-on:click.prevent="toBaidu(1)" >欢迎访问网站</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
//表达式字符串
text:"color:red"
}
}
},
//当前组件的所有方法
methods:{
//跳转到百度
toBaidu(a){ // toBaidu:function(){}
console.dir(a);
location.href = "https://www.baidu.com"
}
}
}
</script>
简单写法:v-on用@替代
如:当点击时触发函数 @click=“函数”
<template>
<div class="hello">
<!-- 点击h1标签跳转到百度首页 -->
<h1 @dblclick="toBaidu(1)" >欢迎访问网站</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
//表达式字符串
text:"color:red"
}
}
},
//当前组件的所有方法
methods:{
//跳转到百度
toBaidu(a){ // toBaidu:function(){}
console.dir(a);
//location.href = "https://www.baidu.com"
},
...
aa(){
this.toBaidu();// this调用别的方法
this.person.text = "123"; // this访问data值
}
}
}
</script>
键盘输入-实现事件触发
敲击回车,实现方法调用
<template>
<div class="hello">
<!-- 键盘键入回车就跳转到百度首页 -->
<h1>欢迎访问网站</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
person:{
//表达式字符串
text:"color:red"
}
}
},
mounted(){//dom渲染完成
//添加一个监听键盘操作的监听器
window.addEventListener('keydown', this.mykey);
},
//当前组件的所有方法
methods:{
//绑定到监听键盘输入的回调方法
mykey(param){
if(param.keyCode == 13){// 13 代表敲击回车
this.toBaidu();
}
},
//跳转到百度
toBaidu(){ // toBaidu:function(){}
location.href = "https://www.baidu.com"
}
}
}
</script>
js中所有keycode列表
https://blog.csdn.net/fghyibib/article/details/120670221?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-120670221-blog-122497397.pc_relevant_multi_platform_whitelistv3&spm=1001.2101.3001.4242.2&utm_relevant_index=4
5.v-if 、v-show
v-if:
true: 标签或者组件被挂载
false:标签或者组件删除或销毁v-show: 通过display样式控制组件显示隐藏
true: 标签或者组件 - 显示状态
false:标签或者组件 - 被隐藏
<template>
<div class="hello">
<!--
v-if:
true: 标签或者组件被挂载
false:标签或者组件删除或销毁
-->
<h1 v-if="isOk">欢迎访问网站</h1>
<!--
v-show: 通过display样式控制组件显示隐藏
true: 标签或者组件 - 显示状态
false:标签或者组件 - 被隐藏
-->
<h1 v-show="isOk">欢迎访问网站2</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
isOk:true
}
},
mounted(){//dom渲染完成
},
//当前组件的所有方法
methods:{
}
}
</script>
v-if挂载过程
当v-if值为true时:组件会进入创建阶段—渲染阶段
如果父组件加载子组件时,子组件被v-if=“false” 描述时,子组件是不会被加载
当v-if值为false是:组件会进入销毁阶段
v-show挂载过程
当v-show值为true时:组件被显示-不会调用生命周期钩子
如果父组件加载子组件时,子组件被v-show=“false” 描述时,子组件会加载但是不显示而已
当v-show值为false是:组件被隐藏-不会调用生命周期钩子
v-if根据boolean控制组件加载,v-show根据boolean控制组件显示隐藏不管值为true还是false都会被提前加载
6.v-else\v-else-if
多条件判断指令
注意:v-if v-els-if v-else要注意编写的顺序和数量,v-else只能有一个,v-else-if可以有多个
注意标签之间的顺序,不要有间隔
<Test1 v-if="isOk"></Test1> // 独立的判断
<h1 v-if="name=='鸡仔'">123</h1> //2 行 一组判断逻辑
<Test2 v-else></Test2>
7.v-for-有序列表的遍历 循环指令
v-for=“(循环中的每个对象,循环遍历的下标) in 要循环的集合数组”
简写-只取出集合中的对象: v-for=“循环中的每个对象 in 要循环的集合数组”
循环中必填参数
key:描述循环的标签是独一无二的,只要绑定一个唯一值属性即可,提供给VDom更新元素
<template>
<div class="hello">
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
<!--
v-for="(循环中的每个对象,循环遍历的下标) in 要循环的集合数组"
-->
<tr v-for="(item,index) in userList" :key="index">
<!-- 循环中插入的数据就使用item对象访问属性值用插值表达式输出 -->
<td>{
{item.id}}</td>
<td>{
{item.name}}</td>
<td>{
{item.age}}</td>
</tr>
</table>
</div>
</template>
<script>
//引入组件
import Test1 from './Test.vue';
import Test2 from './Test2.vue';
export default {
name: 'HelloWorld',
//注册组件
components:{Test1,Test2},
data () {
return {
isOk:false,
name:"鸡仔",
userList:[
{
name:"蔡徐坤",
age:18,
id:101
},
{
name:"小鸡仔",
age:19,
id:102
}
]
}
},
mounted(){//dom渲染完成
},
//当前组件的所有方法
methods:{
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
8.v-for - 遍历map\对象
v-for=“(对象的属性值,对象的属性名称,属性的序号) in 要迭代对象” :key=“唯一值”
<template>
<div class="hello">
<!-- v-for="(对象的属性值,对象的属性名称,属性的序号) in 要迭代对象" :key="唯一值" -->
<h1 v-for="(value,key,index) in userData" :key="index">
[{
{index}}]{
{key}}====={
{value}}
</h1>
</div>
</template>
<script>
//引入组件
import Test1 from './Test.vue';
import Test2 from './Test2.vue';
export default {
name: 'HelloWorld',
//注册组件
components:{Test1,Test2},
data () {
return {
isOk:false,
name:"鸡仔",
userData:{
name:"ikun",
age:0,
id:101
}
}
},
mounted(){//dom渲染完成
},
//当前组件的所有方法
methods:{
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
9.v-model 表单数据绑定
在传统H5开发的方式下,表单的值一般是用value属性控制,但是进过测试动态绑定表单标签的value属性无法实现表单值的变化,这时我们需要使用v-model指令实现表单数据的动态绑定
1. v-model在文本域中的使用方法
<template>
<div class="hello">
<input v-model="name"/>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
name:null
}
}
}
</script>
<style scoped>
</style>
注意:使用vue后,表单元素绑定数据就要使用v-model而不要再使用value属性了
1.v-model.lazy
效果:当填写完成,选中效果移除之后数据才更新
<input v-model.lazy="name"/>
2. v-model.number
效果:在填写文本时,只能填写数字
注意:只有填写文字是数字开头才有用,而且从数字开头截取字符直到出现第一个非数字位置结束,如:1a2b ===> 1
<input v-model.number="name"/>
推荐如果是纯数字校验,使用type=“number”
<input type="number" v-model.number="name"/>
v-model.trim
去除前后空格的方式
<input v-model.trim="name"/>
2. v-model在选择器中的使用方法
<!-- 如果需要回填自动选中选项,只要改变v-model绑定的数据值就ok -->
<select v-model="name">
<!-- 描述属性是数值类型时,需要添加v-bind -->
<option :value="1">昆明</option>
<!-- 描述属性是boolean类型时,需要添加v-bind -->
<option :value="true">临沧</option>
<option value="3">蒙自</option>
</select>
3. v-model 在单选和复选框中的使用方法
单选框
<template>
<div class="hello">
<input type="radio" name="sex" :value="1" v-model="sexCode"/>男
<input type="radio" name="sex" :value="2" v-model="sexCode"/>女
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
sexCode:null
}
}
}
</script>
<style scoped>
</style>
复选框
<template>
<div class="hello">
<input type="checkbox" name="like" :value="1" v-model="likeCode"/>吃鸡
<input type="checkbox" name="like" :value="2" v-model="likeCode"/>lol
<input type="checkbox" name="like" :value="3" v-model="likeCode"/>王者别嚣张
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
likeCode:[]// checkbox情况下,初始化值一定是要一个空数组
}
}
}
</script>
<style scoped>
</style>
4. v-model使用在文本域中
<template>
<div class="hello">
<textarea v-model="name"></textarea>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
name:null
}
}
}
</script>
<style scoped>
</style>
10.过滤器
目的:可以改写插值表达式的显示内容
<template>
<div class="hello">
<!-- userData.name值nameFilter过滤器中 -->
<!-- 过滤器可以改写插值表达式的内容 -->
<h1>{
{ userData.name | nameFilter | nameFilter2 }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
isOk:false,
name:"鸡仔",
userData:{
name:"ikun",
age:0,
id:101
}
}
},
//过滤器
filters:{
//自定义过滤器
nameFilter:function(value){
console.dir(value);
//要定义返回值
return "欢迎管理员:"+value+",登录系统";
},
nameFilter2:function(value){
console.dir(value);
return value+"!!!!!!"
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
v-bind指令也能配合过滤器使用
<h1 :title="userData.name | nameFilter">点击查看用户信息</h1>
vue3.0已经弃用过滤器
11. 计算属性
计算属性使用场景:
和过滤器比较:
过滤器:参数只能是插值表达式中|之前的值注入到过滤器的参数中,过滤器无法访问data绑定的数据
计算属性:参数可以是在计算属性调用时的实参也可以访问data绑定的数据(this访问)
使用计算属性-无参的方法
<h1>{
{ nameComputed }}</h1>
//计算属性
computed:{
//自定义计算属性
nameComputed:function(){
return this.userData.name.split('').reverse().join('');
}
}
使用计算属性-可以传递参数的方法
<h1>{
{ nameComputed("1",1,3) }}</h1>
//计算属性
computed:{
//自定义计算属性
nameComputed(){
return function(value,value2,value3){
console.dir(value);
return this.userData.name.split('').reverse().join('');
}
}
}
method方法能不能使用到插值表达式中
是可以的,但是推荐使用计算属性完成
method和computed的区别
计算属性:
计算属性会使用浏览器缓存进行数据的存储和计算
计算属性可以根据行为是读取还是参数赋值区分出get和set两种方法模式
mycomputed:{
get:function(){
// 无参调用计算属性时触发
console.dir("get");
return "get";
},
set:function(){
// 有参调用计算属性触发
console.dir("set");
return "set";
}
}
而方法每次调用都需要经过函数执行的读写,没有任何缓存的实现,所以性能较差,当开发目的只是为了改变插值表达式的值内容的情景时,推荐使用计算属性完成
12.监听器
作用:监听data绑定数据的变化
注意:要监听的数据如果保存在对象中话写法有所区别
<template>
<div class="hello">
<h2>{
{ userData.age }}</h2>
<button @click="userData.age +=1">点击我+1!</button>
<button @click="userData.age -=1">点击我-1!</button>
<h2>{
{ aa }}</h2>
<button @click="aa +=1">点击我+1!</button>
<button @click="aa -=1">点击我-1!</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
isOk:false,
name:"鸡仔",
aa:0,
userData:{
name:"ikun",
age:0,
id:101
}
}
},
methods:{// 普通方法就像js中的函数 function
say(){
return "123456";
}
},
watch:{//监听器- 可以监听data绑定数据的变化
// data绑定数据的名称(新变化的值,变化之前的值)
aa(newValue,oldValue){
console.dir(newValue+"-----"+oldValue);
},
//要监听的数据是存在对象中的
"userData.age"(newVal,oldVal){
console.dir(newVal+"-----"+oldVal);
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
深度监听
多组件共用data值的时候会使用
"userData.data.data.age":{
immediate:true,// 深度监听立即执行
deep: true,// 开启深度监听
handler(newVal,oldVal){
console.dir(newVal+"-----"+oldVal);
}
}
在昨天的学生信息列表功能下实现前端的:添加、编辑功能
- 添加功能:
- 在表格上方会有一个添加按钮
- 点击添加按钮弹出一个div,里面有学生信息添加内容的表单以及保存、重置表单按钮
- 填写完数据点击保存,弹窗关闭,表格数据刷新
- 编辑功能
- 表格中多一列操作列
- 操作列对应每一行中有编辑按钮
- 点击编辑弹出编辑div,里面有学生信息编辑内容的表单以及保存编辑
- 填写完数据点击保存,弹窗关闭,表格数据刷新
- 实现添加表单和编辑表单公用一个div和表单内容,通过判断实现
13. 动态样式绑定方法
动态修改class属性的方法实现样式变化
1.对象语法
<template>
<div class="hello">
<!-- isUse为true则class属性值为class="div1" 为false class="" -->
<div :class="{ div1: isUse , hide : isUse2}"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
isUse: false,
isUse2:false
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.div1 {
width: 100px;
height: 100px;
background-color: red;
}
.div2 {
width: 100px;
height: 100px;
background-color: yellow;
}
.hide{
display: none;
}
</style>
2. 数据绑定实现class属性变化
<template>
<div class="hello">
<div :class="myDivClass"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
myDivClass:{
div1:true,// 需要添加div1 值
hide:false// hide值不添加
}
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.div1 {
width: 100px;
height: 100px;
background-color: red;
}
.div2 {
width: 100px;
height: 100px;
background-color: yellow;
}
.hide{
display: none;
}
</style>
3. 通过数组的方式控制class属性值内容
<template>
<div class="hello">
<div :class="[activeDiv1,activeHid]"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
activeDiv1:'div1', //属性值是样式名称
activeHid:'hide'
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.div1 {
width: 100px;
height: 100px;
background-color: red;
}
.div2 {
width: 100px;
height: 100px;
background-color: yellow;
}
.hide{
display: none;
}
</style>
数组中可以使用表达式完成样式的选择
<template>
<div class="hello">
<!-- 数组中可以使用表达式完成样式的选择 -->
<div :class="[isUser==true?activeDiv1:'xx',activeHid]"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
activeDiv1:'div1', //属性值是样式名称
activeHid:'hide',
isUser:false
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.div1 {
width: 100px;
height: 100px;
background-color: red;
}
.div2 {
width: 100px;
height: 100px;
background-color: yellow;
}
.hide{
display: none;
}
</style>
动态修改内联样式style属性的方法
1.嵌入对象的方法
<template>
<div class="hello">
<!-- 样式值实现动态绑定 -->
<div :style="{color:fontColor,backgroundColor:bgColor,with:'100px',height:'100px'}"></div>
<input v-model="bgColor" />
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
fontColor:'red',
bgColor:'yellow'
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
2. 数据绑定style属性方法
<template>
<div class="hello">
<!-- 样式值实现动态绑定 -->
<div :style="myStyle"></div>
<input v-model="myStyle.backgroundColor" />
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
myStyle:{// 需要绑定到style属性中的对象要求:属性名称是样式名称,属性值是样式值
color:'red',
backgroundColor:'yellow',
width:'100px',
height:'100px'
}
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
14.组件开发方法
1.引入使用组件方法
子组件代码
<!-- Dom页面 -->
<template>
<div id="TestIndex">
测试页面1
</div>
</template>
<!-- 组件js -->
<script>
export default {
name: "TestIndex",
data() {
return{
}
},
};
</script>
<!-- CSS代码 -->
<style scoped></style>
父组件代码
<template>
<div class="hello">
<!-- 3.通过标签的方式引入组件,标签名称就是组件名称 -->
<Test />
</div>
</template>
<script>
//1. 导入要使用的组件 @代表的就是src目录路径,有点像classpath
import Test from '@/components/Test.vue';
export default {
name: "HelloWorld",
components:{Test},// 2.注册声明组件使用
data() {
return {
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
2.子组件接收父组件数据
子组件要定义能接收的数据有些什么(组件参数)
props属性定义
注意:子父组件值传递是值的拷贝,不会传递地址
子组件写法
<!-- Dom页面 -->
<template>
<div id="TestIndex">
测试页面1{
{ name }}
<input v-model="name">
</div>
</template>
<!-- 组件js -->
<script>
export default {
name: "TestIndex",
props:{//组件接收参数定义 使用props参数值的方式和使用data绑定数据的方法一样
// 注意不要和data中的数据名称重复
name:{
type:String,// String:字符串字符类型 Number:数值类型 Array:集合数组类型 Object:对象、map类型
default:'只因你太美' //默认值
},
age:{
type:Number,
default:18
}
},
watch:{
name:function(newV,oldV){
console.dir("监听:"+newV+"---"+oldV);
}
},
data() {
return{
sonName:this.name //访问props参数方法和访问data值方法一致
}
},
methods:{
aa(){
console.dir(this.name);//访问props参数方法和访问data值方法一致
}
}
};
</script>
<!-- CSS代码 -->
<style scoped></style>
父组件传递方法
<template>
<div class="hello">
<!-- 3.通过标签的方式引入组件,标签名称就是组件名称 -->
<!-- 给子组件props参数传值是通过标签属性传递的 -->
<Test :name="fatherName" :age="12" />
</div>
</template>
<script>
//1. 导入要使用的组件 @代表的就是src目录路径,有点像classpath
import Test from '@/components/Test.vue';
export default {
name: "HelloWorld",
components:{Test},// 2.注册声明组件使用
data() {
return {
fatherName:"蔡徐坤"
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
当子组件点击关闭按钮时,父组件要接收关闭事件的回调
需要子组件通知父组件,有事情发生,让父组件能够接收这个消息
3. 子组件与父组件回调方法
能实现子组件将数据传递到父组件
案例:点击子组件的关闭按钮,实现父组件div隐藏
子组件代码
<!-- Dom页面 -->
<template>
<div id="TestIndex">
<button @click="sonClose">关闭</button>
</div>
</template>
<!-- 组件js -->
<script>
export default {
name: "TestIndex",
data() {
return{
}
},
methods:{
sonClose(){//子组件点击了关闭按钮
//让父组件接收到我的这个信息
// 如果需要传递参数,接收时一定要按照传递时的顺序取参数
this.$emit("sClose","cxk",123);// 封装了一个方法名叫sClose的回调函数通知父组件
}
}
};
</script>
<!-- CSS代码 -->
<style scoped></style>
父组件代码
<template>
<div class="hello">
<div class="myDiv" v-if="isShow">
<!-- 回调函数接收的方法不要定义参数列表 -->
<Test @sClose="fatherFunction"/>
</div>
</div>
</template>
<script>
//1. 导入要使用的组件 @代表的就是src目录路径,有点像classpath
import Test from '@/components/Test.vue';
export default {
name: "HelloWorld",
components:{Test},// 2.注册声明组件使用
data() {
return {
isShow:true
};
},
methods:{
//父组件接收子组件回调的方法
fatherFunction(param,param2){
console.dir(param);
console.dir(param2);
this.isShow = false;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.myDiv{
width: 200px;
height: 200px;
background-color: aqua;
}
</style>
- 定义一个子组件,功能是:通过父组件传递的列表数据实现一个动态下拉框
- 当下拉框选中数据时,要回调一个时间给父组件(change\selected)
- 实现下拉框清空功能,点击清空清空select选择的内容,然后回调一个事件给父组件(clear\qingkong)
4.子组件定义好后,父组件引入组件,试用是否正常
15. 路由
1. 路由是什么
2. 路由的三个对象
route:首先它是个单数,译为路由,即我们可以理解为单个路由或者某一个路由;( 单个路由信息 )
routes:它是个复数,表示多个的集合才能为复数;即我们可以理解为多个路由的集合,JS中表示多种不同状态的集合的形式只有数组和对象两种,事实上官方定义routes是一个数组;所以我们记住了,routes表示多个数组的集合;(整个项目中的所有路由信息)
router:译为路由器,上面都是路由,这个是路由器,我们可以理解为一个容器包含上述两个或者说它是一个管理者,负责管理上述两个;举个常见的场景的例子:当用户在页面上点击按钮的时候,这个时候router就会去routes中去查找route,就是说路由器会去路由集合中找对应的路由;(对象,可以实现路由的多种功能跳转)
3.如何配置路由
什么地址可以访问哪个组件,描述一下路由信息
- 编写组件页面
2.打开路由配置文件
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
//1. 导入需要配置路由的组件
import Test2 from '@/components/Test2.vue';
Vue.use(Router)
export default new Router({
// 所有路由信息-集合
routes: [// 第一个路由记录就是欢迎页
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
meta:{
index:0,
name:"首页"
}
},
{
// 2.编写路由
path: '/test2',// 访问路径
name: 'Test2', //路由组件名称
component: Test2, //关联组件
meta:{
index:1, // 组件顺序-按照组件关系写
name:"测试页面2" // 路由组件名称-中文描述-提供面包屑使用
}
}
]
})
改变路由访问的方法
export default new Router({
mode: 'history',// 路由地址前面就不会有/#/
4. 路由跳转方法
1. router-link标签
<!-- 效果类似a标签 -->
<!-- <a href="/test2">XXXX</a> -->
<router-link to="/test2">跳转到test2页面</router-link>
2. $router对象
puish方法- 是会把路由跳转的记录添加到浏览器的缓存记录中的,就可以使用浏览器的前进和后退功能
replace方法-则不会将访问的数据添加到记录中
1.push方法- 直接传递路由地址字符串
<template>
<div class="hello">
<button @click="doRouter">点击跳转</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
};
},
methods:{
//路由跳转方法
doRouter(){
this.$router.push('/test2');
}
}
};
</script>
2.push方法-传递一个路由信息对象
<template>
<div class="hello">
<button @click="doRouter">点击跳转</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
routeData:{
path:'/test2'
}
};
},
methods:{
//路由跳转方法
doRouter(){
this.$router.push(this.routeData);
}
}
};
</script>
3.push-传递的路由信息对象-跳转的页面是通过name确定
<template>
<div class="hello">
<button @click="doRouter">点击跳转</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
routeData:{
name:"Test2" // 路由定义的index.js中定义路由的name值
}
};
},
methods:{
//路由跳转方法
doRouter(){
this.$router.push(this.routeData);
}
}
};
</script>
4.replcae方法
和push用法相同
// 字符串
this.$router.replace('/home/first')
// 对象
this.$router.replace({ path: '/home/first' })
// 命名的路由
this.$router.replace({ name: 'home', params: { userId: wise }})
5. go方法
//前进一步 相当于history.forward()
this.$router.go(1)
、
//后退一步 相当于history.back()
this.$router.go(-1)
this.$router.go(10)
3. 嵌套子路由
使用场景: 企业管理系统后端,左侧菜单右侧组件刷新的界面
主页:
<!-- Dom页面 -->
<template>
<div id="Main">
<h1>主页</h1>
<router-link to="/user">用户管理</router-link>
<router-link to="/role">角色管理</router-link>
<!-- 路由切换视图标签 -->
<router-view />
</div>
</template>
<!-- 组件js -->
<script>
export default {
name: "Main",
data() {
return {};
}
};
</script>
<!-- CSS代码 -->
<style scoped></style>
路由配置
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Main from '@/components/main'
//1. 引入组件
import User from '@/components/user'
import Role from '@/components/role'
Vue.use(Router)
export default new Router({
mode: 'history',// 路由地址前面就不会有/#/
// 所有路由信息-集合
routes: [// 第一个路由记录就是欢迎页
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
meta:{
index:0,
name:"登录页面"
}
},
{
path: '/main',
name: 'Main',
component: Main,
meta:{
index:1,
name:"首页"
},
children:[// 子路由!!!!!!!
{
path: '/user',
name: 'User',
component: User,
meta:{
index:1-1,
name:"用户管理"
}
},
{
path: '/role',
name: 'Role',
component: Role,
meta:{
index:1-2,
name:"角色管理"
}
}
]
}
]
})
5.路由传参
1. 在路由路径上拼接参数- 刷新页面参数也不会丢失
路由配置文件中,在path属性上声明会出现参数的位置
{
path: '/:id', // 在/ 路径之后 会传递一个 名字叫id的参数
name: 'HelloWorld',
component: HelloWorld,
meta:{
index:0,
name:"登录页面"
}
},
调用路由跳转是传递参数
注意:只能传递简单的字符串和数值、boolean类型,不能传递对象
this.$router.push({ path:`/main/${this.param}`});
目标路由组件中获取参数
<!-- Dom页面 -->
<template>
<div id="Main">
<h1>主页</h1>
<h1>{
{
$route.params.id }}</h1>
</div>
</template>
2.在调用路由方法时,添加params属性传递参数-刷新页面参数就丢失
路由配置文件就不用修改了
调用路由跳转方法
该方法是支持对象传递的
// 想要使用params传递参数,路由跳转的方法必须使用name指定路由页面才行
this.$router.push({
name:"Main",params:this.param});
3.在调用路由方法是,添加query属性传递参数-刷新页面也不会丢失参数
路由配置文件就不用修改了
调用路由跳转方法
该方法是支持对象传递的
this.$router.push({
path:"/main",query:this.param});
路由目标页面取参数,要通过query参数取得
this.loginUser = this.$route.query.name;
总结路由传参3种方法:
1.路径拼接法: 如果面有必须要初始化或者必须传递参数才能使用的场景时在使用
2.params方法:对传递的参数进行加密,但是数据传输是一次性的
3.query方法:对参数没有进行加密,直接暴露在url中
routes对象访问
this.$router.options.routes
能够访问当前项目的所有路由信息
6.Vue路由跳转加载进度条
1. 使用Nprogress
在项目的窗口中执行
cnpm install nprogress
2.main.js中引入组件和样式
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'// nprogress样式文件
3.路由组件钩子函数配置
两个钩子:路由跳转前和跳转后
// 路由的钩子函数是main.js中配置的
// 路由跳转之前
router.beforeEach((to, from , next) => {
// 开启进度条
NProgress.start();
// 这个一定要加,没有next()页面不会跳转的。这部分还不清楚的去翻一下官网就明白了
next();
});
//当路由跳转结束后
router.afterEach(() => {
// 关闭进度条
NProgress.done()
})
- 需要实现一个增删改查分页的表格组件
16. axios组件
作用: 与ajax一样,底层实现就是js-ajax,写法要比之前学习的JQuery、js的ajax都要简单
安装步骤
//1. 在项目窗口中执行
cnpm install axios
main.js中配置axios内容
import axios from 'axios'
Vue.prototype.$axios = axios //全局属性
全局属性的定义方法
在main.js中定义
// 定义全局属性的方法
// Vue.prototype.自定义属性名 = 组件对象
// 属性命名规则:$+属性名
// 在组件中使用全局属性: this.$axios
Vue.prototype.$axios = axios //全局属性
跨域问题处理、请求服务地址配置
什么是跨域?
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
注意: 协议+主机+端口有一个不相同就会出现跨域问题
1.配置BaseUrl,在main.js文件中
axios.defaults.baseURL = '/api' //关键代码,/api之后替换的就是 http://localhost:8090
2.配置代理,在config文件夹下的index.js文件中的proxyTable字段
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
// 配置到这里!!!!
'/api': {
// 配置了一个静态地址代理
target:'http://localhost:8090', // 后端服务地址以及端口号
changeOrigin:true, // 可以跨域
pathRewrite:{
'^/api': ''
}
}
},
- main.js 修改 axios全局属性的创建方法
Vue.prototype.$axios = axios.create({
baseURL:'/api',
timeout:30000
})
- 把项目停止,执行cnpm install ,再启动项目
- 测试案例
getData() {
console.dir(this);
// 在axios代码中要使用this关键字访问data或者方法等等vue组件内容的话需要定一个别名变量
let _this = this;
this.$axios
.get("goods/goods/getGoodsByID?id=101")
.then(function(res) {
_this.resData = res.data;
})
.catch(function(error) {
// 请求失败处理
console.log(error);
});
}
4种请求
GET请求
- 参数拼接在url后面
// 直接在 URL 上添加参数 ID=12345
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
- 传入一个有params属性的参数
this.$axios
.get("goods/goods/getGoodsByID",{
params:{
// 写键值对参数内容
id:101
}
})
POST请求
请求已经将数据封装为json数据发送后端了,所以在后端编写controller方法时,记得要使用@RequestBody注解接收参数
put\delete请求写法和post一致
this.$axios
.post("goods/goods/testpost",{
// 参数传递的方法和GET不同
name:"张三",
price:18.9
})
批量提交请求方法
需要使用的是axios组件对象的all方法,而以上案例中使用的$axios对象是通过组件对象.create创建的实例
所以我们需要从新定义一个全局的axios组件对象
main.js中定义组件对象全局属性
Vue.prototype.$VueAxios = axios; // all 再用该对象 新配置的组件对象
Vue.prototype.$axios = axios.create({
// get post delete put
baseURL:'/api',
timeout:30000
})
批量接口调用方法
getData1() {
return this.$axios
.post("goods/goods/testpost",{
name:"张三",
price:18.9
});
},
getData2() {
return this.$axios.get("goods/goods/getGoodsByID?id=101");
},
//合并提交方法
getAllData(){
let _this = this;
console.dir(this.$axios);
this.$VueAxios.all([_this.getData1(),_this.getData2()]) // 按照数组顺序调用
.then(_this.$VueAxios.spread(function (res1, res2) {
// 根据调用方法的数量定义接收对应方法返回的数据参数
// 当所有的方法执行完成且都有返回值之后
console.dir("请求完成");
console.dir(acct);
console.dir(perms);
}));
}
请求拦截器
请求拦截器的作用
在axios发送请求到后端之前进行拦截,可以修改请求的参数等内容
写在main.js中
// http request 请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
return config;
}, error => {
// 对请求错误做些什么
return Promise.reject(error);
});
响应拦截器
作用:
所有的请求返回响应时都会进入改拦截器
// 响应拦截器
Vue.prototype.$axios.interceptors.response.use(response => {
console.dir(response);
if(response.data.code == "9999"){
//系统异常
// 统一错误提示弹窗
}else if(response.data.code == "-1"){
// 登录会话失效
// 使用路由返回到登录页面
}
return response;
},error => {
if (error.response) {
// 返回接口返回的错误信息
return Promise.reject(error.response.data);
}
});
17. 子组件自定义v-model
v-model: 只能在表单功能上出现
案例:子组件实现性别单选,v-model实现绑定性别的code值,子父组件修改v-model绑定的子父数据都会改变
子组件写法
<template>
<div id="Test1">
<!-- 子组件:性别的单选框 怎么设计和实现v-model -->
<input type="radio" :value="1" :checked="isManChecked" name="sex" @change="sexChange(1)" />男
<input type="radio" :value="2" :checked="isWoManChecked" name="sex" @change="sexChange(2)"/>女
</div>
</template>
<script>
export default {
name: "Test1",
props:{
sexCode:{
type:Number
}
},
//v-model绑定数据
model:{
prop:'sexCode', // v-model绑定的参数是sexCode字段
event:'onchange' // v-model数据更新的回调事件叫什么(v-model更改过程是依赖事件)
},
watch:{
sexCode:function(newV,oldV){
if(newV==1){//男选中
this.isManChecked = true;
this.isWoManChecked = false;
}else{//选中女
this.isManChecked = false;
this.isWoManChecked = true;
}
}
},
data() {
return {
isManChecked:false,
isWoManChecked:false
};
},
methods:{
sexChange(param){
this.$emit("onchange",param); // 第二个参数,就是更新父组件v-model绑定数据的值
}
}
};
</script>
<!-- CSS代码 -->
<style scoped></style>
父组件
<Test1 v-model="data" />
18.插槽
作用:能够将指定的标签放置在组件的插槽容器中,可以规范组件内容组成也可以灵活配置组件内容
插槽标签
<slot>。。</slot>
插槽-默认插槽
也叫无具名插槽,一般用在父组件快速批量替换子组件默认内容时使用
子组件定义
<template>
<div id="Test1">
<div class="div1">
<!-- 默认插槽写法:<slot> -->
<slot>默认插槽的文字1</slot>
</div>
<div class="div2">
<slot>默认插槽的文字2</slot>
</div>
</div>
</template>
父组件改变默认插槽方法
<Test1 v-model="sexCode" >
<!-- 在子组件中添加html代码段就会替换默认插槽信息 -->
<h1>XXX</h1>
<h1>XXX222</h1>
</Test1>
具名插槽
子组件定义
<template>
<div id="Test1">
<div class="div1">
<slot name="one">插槽的文字1</slot>
</div>
<div class="div2">
<slot name="two">插槽的文字2</slot>
</div>
</div>
</template>
父组件
<Test1 v-model="sexCode" >
<!-- 具名插槽赋值方法:template标签 v-slot:插槽的name值 -->
<template v-slot:one>
<h1>XXX</h1>
</template>
</Test1>
slot属性赋值具名插槽方法
<!-- 具名插槽赋值方法:可以使用在标签上 slot="插槽名称" -->
<div slot="one">
<h1>XXX</h1>
</div>
对象作用域插槽
子组件
<template>
<div id="Test1">
<div class="div1">
<!-- 绑定了一个叫obj的属性在插槽上 -->
<slot :obj2="objData" :obj="objData">插槽的文字1</slot>
</div>
</div>
</template>
<script>
export default {
name: "Test1",
data() {
return {
objData:{
name:"张三",
age:18
}
};
},
methods:{
}
};
</script>
父组件
<Test1 v-model="sexCode" >
<!-- template标签声明v-slot="定义一个变量接收子组件插槽中定义的对象" -->
<template v-slot="objData">
<!-- 对象.插槽属性名.插槽属性对象的属性值 -->
<h1>{
{ objData.obj2.name }}</h1>
</template>
</Test1>
19. Vuex状态管理
1.安装方法
在项目cmd窗口中执行
cnpm install vuex
创建一个store.js的文件,
在src目录下创建vuex文件夹,在文件夹中创建store.js文件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state:{
},
getters:{
},
mutations:{
},
actions:{
}
});
在main.js中导入组件
//导入vuex组件内容
import Vuex from 'vuex';
import store from './vuex/store'
Vue.use(Vuex);
Vue.prototype.$store = store;
// 修改原有的new Vue构造器
new Vue({
el: '#app',
router,
store, // 添加到全局组件
components: {
App },
template: '<App/>'
})
使用方法
1. 设置保存数据
在state对象中描述要保存的数据
export default new Vuex.Store({
state:{
// 共享的数据
count:0
},
2. 修改数据
1.action - 无参调用方法
actions:{
// 操作state里的数据方法
addCount(){
// 每次调用让count数据+1
this.state.count++;
},
调用方法
// 调用了vuex中action中的addCount方法,无参调用
this.$store.dispatch("addCount"); // 字符串的action方法名
2.action - 有参调用方法
// 形参1: vuex对象
// 形参2: 传入的数据(如果要传递多个参数,就封装到对象中---map、集合)
addCount2(obj,param){
this.state.count += param;
}
调用的方法
this.$store.dispatch("addCount2",123);
3. mutations - 无参调用
mutations:{
m_addCount(){
this.state.count++;
}
},
调用方法
this.$store.commit("m_addCount");
4.mutations - 有参调用
// 形参1: state对象
// 形参2: 传入的数据(如果要传递多个参数,就封装到对象中---map、集合)
m_addCount2(obj,param){
console.log(obj); // state对象
this.state.count += param;
}
调用方法
this.$store.commit("m_addCount2",123);
3. 获取值
getters
getters:{
// 获取值的操作
getCount(obj){
// 参数注入了当前vuex的state对象
console.dir(obj.count);
return obj.count; // $store.getters.getCount
}
},
调用方法
this.$store.getters.getCount
mutations和action 方法使用选择
如果需要异步快速执行就使用action方法,如果是需要保证数据读写安全通过等待就使用mutations方法
action方法是会返回promise函数,可以使用then和catch描述方法调用成功或失败的节点
而 mutations方法没有,就只是一个简单的函数调用
推荐使用mutations方法,因为同步安全
20.ElementUI
1. 安装
项目cmd窗口执行
cnpm install element-ui
在main.js中导入el组件内容
//导入elementui
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
测试el组件能否使用