Vue基础:Vue基础
TodoList案例:Vue:实现TodoList案例
cd /d 目标文件夹
Vue中使用组件的三大步骤:
1.如何定义一个组件?
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别
区别如下
2.如何注册组件?
3.编写组件标签:
① 局部注册组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>一个重要的内置关系</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<hr>
<!-- 第三步:编写组件标签 -->
<school></school>
<hr>
<!-- 第三步:编写组件标签 -->
<student></student>
<student></student>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//第一步:创建school组件
const school = Vue.extend({ // 传入配置对象
template:`
学校名称:{{schoolName}}
学校地址:{{address}}
`,
// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
data(){ // data 函数式(普通函数),不能书写成对象时,使用对象式时,有引用关系
return {
schoolName:'Tom',
address:'北京昌平'
}
},
})
//第一步:创建student组件
const student = Vue.extend({
template:`
学生姓名:{{studentName}}
学生年龄:{{age}}
`,
//data一定要写成return的形式,因为return能返回一个新的对象
//而之前写的对象形式,如果组件被使用两次,那么两个组件实例使用的同一个data
//a的data数据被修改时,因为数据代理,b中的data数据也被修改
data(){
return {
studentName:'张三',
age:18
}
}
})
new Vue({
el: "#root",
//第二步:注册组件(局部注册)
components:{
school, // 组件名 或者 组件名 school:创建组件时的名字
student
}
})
</script>
</html>
② 全局注册组件
Vue.component(‘hello’,hello) // 组件的名字 组件的位置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 第三步:编写组件标签 -->
<school></school>
<!-- 第三步:编写组件标签 -->
<student></student>
</div>
<div id="root2">
<!-- 第三步:编写组件标签 -->
<hello></hello>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//第一步:创建hello组件
const hello = Vue.extend({
template:`
你好啊!{{name}}
`,
data(){
return {
name:'Tom'
}
}
})
//第二步:全局注册组件
Vue.component('hello',hello) // 组件的名字 组件的位置
//创建vm
new Vue({
el:'#root2',
})
</script>
</html>
1. 关于组件名:
(1)一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
(2)多个单词组成:
第一种写法(kebab-case命名):my-school ‘my-school’
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1)组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行
(2)可以使用name配置项指定组件在开发者工具中呈现的名字
2. 关于组件标签:
第一种写法:
第二种写法:
备注: 不用使用脚手架时,会导致后续组件不能渲染
3. 一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
推荐
单文件组件时,常用
const hello = {
template:`
你好啊!{{name}}
`,
data(){
return {
name:'Tom'
}
}
}
① school 父组件嵌套 student 子组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>一个重要的内置关系</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
//子组件不再页面引用,而在父组件中引用
<school></school>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//创建 student 组件
const student = Vue.extend({
template:`
学生姓名:{{studentName}}
学生年龄:{{age}}
`,
data(){
return {
studentName:'张三',
age:18
}
},
})
//创建 school组件
const school = Vue.extend({ // 传入配置对象
//使用子组件
template:`
学校名称:{{schoolName}}
学校地址:{{address}}
`,
data(){
return {
schoolName:'Tom学校',
address:'北京昌平'
}
},
components:{
student,
}
})
new Vue({
el: "#root",
components:{
school,
}
})
</script>
</html>
②定义hello 组件,其与school平级
<div id="root">
<school></school>
<hello></hello>
</div>
//定义hello组件
const hello = Vue.extend({
template:`{{msg}}
`,
data(){
return {
msg:'欢迎来和Tom一起学习!'
}
}
})
new Vue({
el: "#root",
components:{
school,
hello,
}
})
开发中常用技巧 app组件
作用: 用于管理应用里面所有的组件(vm之下,所有组件之上)
<div id="root">
<app></app>
</div>
//定义app组件
const app = Vue.extend({
template:`
`,
components:{
school, // 引入 school 组件, 不用在引用student 引用父组件即可
hello
}
})
//创建vm
new Vue({
el:'#root',
//注册组件(局部)
components:{app}
})
补充: 容器中也可什么都不写
//创建vm
new Vue({
template:' ',
el:'#root',
//注册组件(局部)
components:{app}
})
关于VueComponent
school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
我们只需要写
或
,Vue解析时会帮我们创建school组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent
关于 this 指向:
(1) 组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】
(2) new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】
VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)
Vue的实例对象,以后简称vm
//不用看,只是怕后面复习不知道在说什么才粘贴进来的
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>VueComponent</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<school></school>
<hello></hello>
school
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//定义school组件
const school = Vue.extend({
name:'school',
template:`
学校名称:{{name}}
学校地址:{{address}}
`,
data(){
return {
name:'Tom',
address:'北京'
}
},
methods: {
showName(){
console.log('showName',this)
}
},
})
const test = Vue.extend({
template:`atguigu`
})
//定义hello组件
const hello = Vue.extend({
template:`
{{msg}}
`,
data(){
return {
msg:'你好啊!'
}
},
components:{test}
})
console.log('@',school) // Vue 的 VueComponent的构造函数
console.log('#',hello) // 每次调用都会 创建一个新的 构造函数对象
// 每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
//创建vm
const vm = new Vue({
el:'#root',
components:{school,hello}
})
</script>
</html>
vc有的功能vm都有,vm有一个功能vc就没有,vm可以通过el决定来为哪个容器服务,vc不可以
① 原型相关知识
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>一个重要的内置关系</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//定义一个构造函数
function Demo(){
this.a = 1
this.b = 2
}
//创建一个Demo的实例对象
const d = new Demo()
console.log(Demo.prototype) // 函数身上的 显示原型属性
console.log(d.__proto__) // 实例身上的 隐式原型属性 统统都指向的了一个对象 原型对象
console.log(Demo.prototype === d.__proto__)
//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
Demo.prototype.x = 99
console.log('@',d.__proto__.x) // 在顺着这条线去找 或者 console.log('@',d.x)
console.log('@',d)
</script>
</html>
② 内置关系 prototype.proto === Vue.prototype
解释: 按照原型链的指向,实例的隐式原型属性,应该指向其缔造者的原型对象。故VC的隐式原型属性指向VC的原型对象,且VC的隐式原型属性本应该指向Object的原型对象,但这里VC的隐式原型属性却指向Vue的原型对象
目的: 让组件实例对象(vc)可以访问到 Vue原型上的属性、方法
在Vue上的x能被组件school访问到
<div id="root">
<school></school>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
//在Vue上的x能被组件school访问到
Vue.prototype.x = 99
//定义school组件 本质 是VueComponent
const school = Vue.extend({
name:'school',
template:`
学校名称:{{name}}
`,
data(){
return {
name:'Tom',
}
},
methods: {
showX(){
//这里可以输出Vue上的x
console.log(this)
console.log(this.x)
}
},
})
//创建一个vm
const vm = new Vue({
el:'#root',
data:{
msg:'你好'
},
components:{school}
})
</script>
安装提示插件:vetur
安装插件后快捷键:
<template>
// 组件的结构
</template>
<script>
// 组件交互相关的代码(数据、方法等等)
</script>
<style>
// 组件的样式
</style>
② 组件的定义 基本使用(简单使用)
<template>
<div class="demo">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
</template>
<script>
export default { // 默认暴露
name:'School', // 组件的名字
data(){
return {
name:'Tom', // 数据
address:'北京昌平'
}
},
methods: {
showName(){
alert(this.name)
}
},
}
</script>
<style>
.demo{
background-color: orange;
}
</style>
<template>
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
</template>
<script>
export default {
name:'Student',
data(){
return {
name:'张三',
age:18
}
}
}
</script>
<template>
// ③ 使用组件
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
// ① 引入组件
import School from './School.vue'
import Student from './Student.vue'
export default {
name:'App', // 汇总所有的组件
// ② 注册组件
components:{
School,
Student
}
}
</script>
③ 创建vm:main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
//后续有介绍render函数
render: h => h(App)
})
④ 容器 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>练习一下单文件组件的语法</title>
</head>
<body>
<!-- 准备一个容器 -->
<div id="root">
<App></App>
</div>
<!-- Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<!-- 先让模板出来在 引入main.js 入口文件-->
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
cli官网
在cmd命令窗口下执行下列步骤
1.全局安装@vue/cli
npm install -g @vue/cli
(过程中不用回车,容易报错,实在不动了再回车试试,等很久的建议配置淘宝镜像)
2.创建项目
切换到要创建项目的目录>,使用命令创建项目
cd /d 目标目录
vue create xxx
(xxx为自定义项目名)
3.选择运行环境(Vue2或3或自定义)
4.启动项目
cd vue_test
npm run serve
5.访问项目
可通过 http://localhost:8080/
访问项目
//
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 开启移动端的理想视口 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- 配置页签图标 -->
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- 引入第三方样式 -->
<link rel="stylesheet" href="<%= BASE_URL %>css/bootstrap.css">
<!-- 配置网页标题 -->
<title>硅谷系统</title>
</head>
<body>
<!-- 当浏览器不支持js时noscript中的元素就会被渲染 -->
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<!-- 容器 -->
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
关于不同版本的Vue
vue.js与vue.runtime.xxx.js的区别
(1) vue.js是完整版的Vue,包含:核心功能+模板解析器
(2) vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器
因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
render函数接收到的createElement函数去指定具体内容
① main.js如果直接这么写会报错
//引入Vue
import Vue from 'vue'
//引入App组件,它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false
//创建Vue实例对象---vm
new Vue({
el:'#app',
template:` `,
components:{App},
})
② 报错原因
引入的vue是阉割版的vue,里面不包含模板解析器
③ 解决方法
解决方法1:使用render(渲染)函数
//render写成最终简化方式的简化步骤如下
// ① 完整写法
new Vue({
el:'#app',
render(createElement) {
return createElement('h1','你好啊')
}
})
// ② 没有使用到this可以写成箭头函数
new Vue({
el:'#app',
render:(createElement)=> {
return createElement('h1','你好啊')
}
})
// ③ 箭头函数左面含有一个参数 可以省略小括号
new Vue({
el:'#app',
render:createElement=> {
return createElement('h1','你好啊')
}
})
// ④ 箭头函数只有一句函数体,并且还return
new Vue({
el:'#app',
render:createElement=> createElement('h1','你好啊')
})
// ⑤ createElement 使用字母替代 render:q=> q('h1','你好啊')
new Vue({
el:'#app',
render:h=> h('h1','你好啊')
})
// 页面上成功返回
// 两个参数
new Vue({
el:'#app',
render:h=> h('h1','你好啊')
})
// 一个参数
import App from './App.vue'
new Vue({
el:'#app',
// render函数完成了这个功能:将App组件放入容器中
render: h => h(App) // 不加入引号 读取变量
})
解决方法2:引入完整版本的Vue
//引入Vue
import Vue from 'vue/dist/vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
template:`你好啊
`,
})
关于引入阉割版vue而不使用vue的原因
举例:
但个人认为实在多此一举了,这个例子也不能让人信服,毕竟工人吃多少饭,完整版vue又能占多少空间?阉割与否就差那么一百多K,随便一张图片都几M了,真的省这么点大小的必要?多写这么个方法就为了解决这么个小问题太费劲了
vue.config.js配置文件
查看Vue的配置文件
vue把核心的配置文件隐藏了,怕用户修改错误,项目跑不起来程序,查看核心配置文件命令:vue inspect > output.js
运行这个命令后会出现 output.js 文件,默认进去报错,在开头加上const a = 就行
但要注意这个文件只是给你看,修改它并不能真的修改到配置
//vue.config.js
module.exports = {
pages: {
index: {
//入口
entry: 'src/main.js',
},
},
lintOnSave:false, //关闭语法检查
}
...
或
<div>
<h1 v-text="msg" id="title"></h1>
<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
<School ref="sch"/>
<School id="sch"/>
</div>
<script>
export default {
name:'App',
components:{},
data() {
},
methods: {
showDOM(){
console.log(document.getElementById("title"))
console.log(this.$refs.title) //1 真实DOM元素
console.log(this.$refs.btn) //2 真实DOM元素
console.log(this.$refs.sch) //3 School组件的实例对象(vc)
}
},
}
</script>
1 输出h1元素
2 school 用 ref 输出vc实例
备注: props是只读的,Vue底层会监测你是否有对props所接受而来的数据进行了修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,则重新复制一份数据到data中,再修改data中的数据即可
在app.vue中引入student 组件并传递参数
<div>
<Student name="李四" sex="女" age="18"/>
</div>
student 中的组件数据不能写死,方便不同学生复用
<script>
export default {
name:'Student',
data() {
console.log(this)
return {
msg:'我是一名热爱学习的学生',
}
},
// 1.简单声明接收
props:['name','age','sex']
// 2.接收的同时对数据进行类型限制
props:{
name:String,
age:Number,
sex:String
}
// 3.接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
sex:{
type:String,
required:true
}
}
}
</script>
如果操作传入过来的数据
如:给年龄加一岁,使用普通参数传参会出现问题
<div>
<h1>{{msg}}</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{age + 1}}</h2>
//直接这么做学生年龄的结果是181,而不是19
</div>
解决办法:
app.vue中绑定age 的值
<div>
<Student name="李四" sex="女" :age="18"/>
</div>
1. 传入的参数不能随意声明
<script>
export default {
name:'Student',
data() {
console.log(this)
return {
msg:'我是一名热爱学习的学生',
}
},
props:['name','age','sex','phone']
}
</script>
2. 外部传递的参数不能直接修改
案例: 修改外部传递参数age的数值
<template>
<div>
<h1>{{msg}}</h1>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{age}}</h2>
<h2>学生年龄:{{myAge+1}}</h2>
</div>
</template>
<script>
export default {
name:'Student',
data() {
console.log(this)
return {
msg:'我是一名热爱学习的学生',
//用myAge去接收age
myAge:this.age // props 的优先级更高,能获取到
}
},
methods: {
updateAge(){
this.myAge++
}
},
//简单声明接收
props:['name','age','sex']
}
</script>
{
data(){...},
methods: {...}
...
}
基本使用
① 观察 student.vue 和 school.vue可以看到有相同的代码段
student.vue
<template>
<div>
<h2 @click="showName">学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男'
}
},
methods: {
showName(){
alert(this.name)
}
},
}
</script>
school.vue
<template>
<div>
<h2 @click="showName">学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
export default {
name:'School',
data() {
return {
name:'Tom学校',
address:'北京',
}
},
methods: {
showName(){
alert(this.name)
}
},
}
</script>
//分别暴露
export const hunhe = {
methods: {
showName(){
alert(this.name)
}
},
mounted() {
console.log('你好啊!')
},
}
export const hunhe2 = {
data() {
return {
x:100,
y:200
}
},
}
③ 向student.vue 和 school.vue 中分别引入并应用
<script>
//引入一个hunhe
import {hunhe,hunhe2} from '../mixin'
export default {
name:'School',
data() {
return {
name:'Tom学校',
address:'北京',
x:666
}
},
//应用混合
mixins:[hunhe,hunhe2],
}
</script>
混合原则
全局混合
在main.js
中引入,而Student.vue 和 School.vue都不进行引入
所有的vc 和 vm 都会得到
//main.js
import {hunhe,hunhe2} from './mixin'
Vue.mixin(hunhe)
Vue.mixin(hunhe2)
对象.install = function(Vue, options){
//1. 添加全局过滤器
Vue.filter(....)
//2. 添加全局指令
Vue.directive(...)
//3.配置全局混入
Vue.mixin(...)
//4. 添加实例方法
Vue.prototype.$myMethod = function(){...}
Vue.prototype.$myProperty = xxx
}
定义一个Vue插件
export default {
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
//定义混入
Vue.mixin({
data() {
return {
x:100,
y:200
}
},
})
//给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = ()=>{alert('你好啊')}
}
}
main.js —> 引入、应用插件 在vm之前
//引入插件
import plugins from './plugins'
//应用(使用)插件
//1,2,3为使用者传参
Vue.use(plugins,1,2,3)
//创建vm
new Vue({
el:'#app',
render: h => h(App)
})
① Student 和 School 组件书写了同类名样式,会发生冲突
// School 组件
<div class="demo">
<h2 class="title">学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
<style>
.demo{
background-color: skyblue;
}
</style>
// Student 组件
<template>
<div class="demo">
<h2 class="title">学生姓名:{{name}}</h2>
<h2 class="atguigu">学生性别:{{sex}}</h2>
</div>
</template>
<style >
.demo{
background-color: pink;
}
</style>
// 组件样式之间发生冲突
② 由于app.js中,Student后引入,所以Student的样式会覆盖掉School的
//app.js
<template>
<div>
<School/>
<hr>
<Student/>
</div>
</template>
<script>
import School from './components/School'
import Student from './components/Student'
export default {
name:'App',
components:{School,Student}
}
</script>
// School 组件
<style scoped>
.demo{
background-color: skyblue;
}
</style>
// Student 组件
<style lang="less" scoped>
.demo{
background-color: pink;
}
</style>
⑤ 注意
补充:
npm i less-loader
,注意和webpack 的版本是否冲突,安装 7版本 npm i less-loader@7npm view webpack versions
<style lang="less" scoped>
.demo{
background-color: pink;
<!-- less 嵌套 -->
.atguigu{
font-size: 40px;
}
}
</style>
案例链接:TodoList案例
LocalStorage的常用API
// 保存数据到 localStorage
localStorage.setItem('key', 'value');
//只能保存字符串形式,json对象需先转成json字符串
let p = {name:'张三',age:18}
localStorage.setItem('person',JSON.stringify(p))
// 从 localStorage 获取数据
let data = localStorage.getItem('key');
// 从 localStorage 删除保存的数据
localStorage.removeItem('key');
// 从 localStorage 删除所有保存的数据
localStorage.clear();
// 获取某个索引的Key
localStorage.key(index)
具体使用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>localStorage</title>
</head>
<body>
<h2>localStorage</h2>
<button onclick="saveData()">点我保存一个数据</button>
<button onclick="readData()">点我读取一个数据</button>
<button onclick="deleteData()">点我删除一个数据</button>
<button onclick="deleteAllData()">点我清空一个数据</button>
<script type="text/javascript" >
let p = {name:'张三',age:18}
function saveData(){
localStorage.setItem('msg','hello!!!')
localStorage.setItem('msg2',666)
localStorage.setItem('person',JSON.stringify(p))
}
function readData(){
console.log(localStorage.getItem('msg'))
console.log(localStorage.getItem('msg2'))
const result = localStorage.getItem('person')
console.log(JSON.parse(result))
// console.log(localStorage.getItem('msg3'))
}
function deleteData(){
localStorage.removeItem('msg2')
}
function deleteAllData(){
localStorage.clear()
}
</script>
</body>
</html>
SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据
SessionStorage的常用API:
// 保存数据到 sessionStorage
sessionStorage.setItem('key', 'value');
//只能保存字符串形式,json对象需先转成json字符串
let p = {name:'张三',age:18}
sessionStorage.setItem('person',JSON.stringify(p))
// 从 sessionStorage 获取数据
let data = sessionStorage.getItem('key');
// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');
// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();
// 获取某个索引的Key
sessionStorage.key(index)
具体使用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>sessionStorage</title>
</head>
<body>
<h2>sessionStorage</h2>
<button onclick="saveData()">点我保存一个数据</button></br>
<button onclick="readData()">点我读取一个数据</button></br>
<button onclick="deleteData()">点我删除一个数据</button></br>
<button onclick="deleteAllData()">点我清空一个数据</button>
<script type="text/javascript" >
let p = {name:'张三',age:18}
function saveData(){
sessionStorage.setItem('msg','hello!!!')
sessionStorage.setItem('msg2',666)
sessionStorage.setItem('person',JSON.stringify(p))
}
function readData(){
console.log(sessionStorage.getItem('msg'))
console.log(sessionStorage.getItem('msg2'))
const result = sessionStorage.getItem('person')
console.log(JSON.parse(result))
// console.log(sessionStorage.getItem('msg3'))
}
function deleteData(){
sessionStorage.removeItem('msg2')
}
function deleteAllData(){
sessionStorage.clear()
}
</script>
</body>
</html>
案例链接:TodoList案例
① 基本代码
School.vue
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
export default {
name:'School',
props:['getSchoolName'],
data() {
return {
name:'Tom学校',
address:'北京',
}
},
}
</script>
<style scoped>
.school{
background-color: skyblue;
padding: 5px;
}
</style>
Student.vue
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
}
</script>
<style lang="less" scoped>
.student{
background-color: pink;
padding: 5px;
margin-top: 30px;
}
</style>
App.vue
<template>
<div class="app">
<h1>{{msg}}</h1>
<School/>
<Student/>
</div>
</template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'你好啊!',
}
},
}
</script>
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
</style>
② School 组件有个按钮,点击按钮把学校名交给App,即子组件传递给父组件
App.vue
<template>
<div class="app">
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
<School :getSchoolName="getSchoolName"/>
<Student/>
</div>
</template>
<script>
export default {
name:'App',
components:{School,Student},
methods: {
getSchoolName(name){
console.log('App收到了学校名:',name)
},
},
}
</script>
School.vue
<template>
<div class="school">
<button @click="sendSchoolName">把学校名给App</button>
</div>
</template>
<script>
export default {
props:['getSchoolName'],
methods: {
sendSchoolName(){
this.getSchoolName(this.name)
}
},
}
</script>
自定义绑定事件方式一:v-on / @
App.vue
<template>
<div class="app">
<h1>{{msg}}</h1>
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
//
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
//
<Student @atguigu="getStudentName"/>
</div>
</template>
<script>
export default {
methods: {
getSchoolName(name){
console.log('App收到了学校名:', name)
}
},
}
</script>
Student.vue
<template>
<div class="student">
<button @click="sendStudentlName">把学生名给App</button>
</div>
</template>
<script>
export default {
methods: {
sendStudentlName(){
//触发Student组件实例身上的atguigu事件
this.$emit('atguigu',this.name)
},
},
}
</script>
二者之间的异同点
自定义绑定事件方式二:$ref
app.vue
在app组件里面,通过app的vc(this.$refs.student),就可以获取到Student组件的实例对象
<div class="app">
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
<!-- <Student @atguigu="getStudentName" @demo="m1"/> -->
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<Student ref="student"/>
</div>
<script>
export default {
// app 挂载完毕时触发mounted
mounted() {
// this.$refs.student 是 Student组件的实例对象
//这里相当于同时在student上绑定事件,并等待事件触发
//$on 当atguigu 被触发的时候 触发回调
this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件
// this.$refs.student.$once('atguigu',this.getStudentName) //绑定自定义事件(一次性) 触发一次后就不能再触发了
//定时器 触发事件后3秒后再启用getStudentName函数
setTimeout(()=>{
this.$refs.student.$on('atguigu',this.getStudentName)},3000)
},
methods: {
getSchoolName(name){
console.log('App收到了学校名:', name)
}
},
}
</script>
触发事件时传递多个参数
// 方式一
school.vue
<script>
methods: {
sendStudentlName(){
this.$emit('atguigu',this.name,666,888,900)
},
},
</script>
app.vue
<script>
methods: {
getStudentName(name,x,y,z){
console.log('App收到了学生名:',name,x,y,z)
},
},
}
</script>
开发中的方式
// 方式一 :
把数据包装成一个对象传递过去
school.vue
<script>
methods: {
sendStudentlName(){
this.$emit('atguigu',{})
},
},
</script>
// 方式二:
es6 写法 正常传递,接收
school.vue
<script>
methods: {
sendStudentlName(){
this.$emit('atguigu',this.name,666,888,900)
},
},
</script>
app.vue
<script>
methods: {
// name 正常结构,其他的参数不管传递多少,整理到params数组上
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
},
},
}
</script>
Student.vue
<template>
<div class="student">
<button @click="add">点我number++</button>
<button @click="unbind">解绑atguigu事件</button>
</template>
<script>
export default {
methods: {
unbind(){
this.$off('atguigu') //解绑一个自定义事件
// this.$off(['atguigu','demo']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
}
},
}
</script>
案例: app在收到Student传入的姓名后,将姓名呈现在页面上
方法一:使用@或v-on
<template>
<div class="app">
<h1>{{msg}},学生姓名是:{{studentName}}</h1>
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
<Student @atguigu="getStudentName" @demo="m1"/>
</div>
</template>
<script>
export default {
data() {
return {
msg:'你好啊!',
studentName:''
}
},
methods: {
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
}
},
}
</script>
方法二:使用$ref
<template>
<div class="app">
<h1>{{msg}},学生姓名是:{{studentName}}</h1>
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<Student ref="student"/>
</div>
</template>
<script>
export default {
data() {
return {
msg:'你好啊!',
studentName:''
}
},
methods: {
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
}
},
mounted() {
this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件
},
}
</script>
注意:
<script>
export default {
data() {
return {
msg:'你好啊!',
studentName:''
}
},
/* methods: {
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
}
},*/
//以下这么写不行
/*
mounted() {
this.$refs.student.$on('atguigu',function(name,...params){
...
}) //绑定自定义事件
console.log(this) // 此时是this 是Student组件的vc
},
*/
//以下这么写可以,但一般没必要
mounted() {
this.$refs.student.$on('atguigu',(name,...params)=>) //绑定自定义事件
console.log(this) // 此时是this 是Student组件的vc
},
}
// 这么写会被默认当做自定义事件
<Student ref="student" @click="show"/>
//加上native 原生的,本来的,才会使用到内置事件
<Student ref="student" @click.native="show"/>
Student.vue
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
}
}
</script>
School.vue
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
export default {
name:'School',
data() {
return {
name:'Tom',
address:'北京',
}
},
}
</script>
App.vue
<template>
<div class="app">
<h1>{{msg}}</h1>
<School/>
<Student/>
</div>
</template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'你好啊!',
}
}
}
</script>
② 实现让所有组件都能看到 组件$bus(即总线)
放在main.js中的 beforeCreate
main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
//绑定在Vue的实例对象上才可以让所有组件“看到”
//$bus = this则是想为$bus绑定一个Vue实例对象,使得$bus可以使用$on,$off,$emit
Vue.prototype.$bus = this //全局事件总线
},
})
③ Student.vue 传给 School 数据
School.vue
<script>
export default {
mounted() {
this.$bus.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
},
beforeDestroy() {
this.$bus.$off('hello') // 销毁 $bus上的事件
//之前不用销毁是因为事件都绑定在足尖上,组件一销毁,事件也跟着销毁
},
}
</script>
Student.vue
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">把学生名给School组件</button>
</div>
</template>
<script>
export default {
methods: {
sendStudentName(){
this.$bus.$emit('hello',this.name)
}
},
}
</script>
案例链接:TodoList案例
使用 PubSubJS
在线文档: https://github.com/mroderick/PubSubJS
安装插件: npm i pubsub-js
相关语法
(1) import PubSub from ‘pubsub-js’ // 引入
(2) PubSub.subscribe(‘msgName’, functon(msgName, data){ })
(3) PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用
(4) PubSub.unsubscribe(token): 取消消息的订阅
具体案例
School.vue
<template>
<div class="school">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'School',
data() {
return {
name:'Tom',
address:'北京',
}
},
mounted() {
// 执行的回调函数中,第一个参数是 函数名(即hello),第二个参数是传过来的 数据
// subscribe 订阅
//每个订阅会返回唯一性id
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
// 如果是普通函数,使用 pubsub 库,则this是undefined
//故应使用箭头函数,则this是vc School
console.log(this)
console.log('有人发布了hello消息,heVlo消息的回调执行了',msgName,data)
})
},
beforeDestroy() {
//销毁要用唯一性id销毁
pubsub.unsubscribe(this.pubId) // 解绑
订阅
},
}
</script>
Student.vue
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">把学生名给School组件</button>
</div>
</template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
mounted() {
},
methods: {
sendStudentName(){
pubsub.publish('hello',666) // publish发布hello,并携带数据666
}
},
}
</script>
TodoList案例博客
$nextTick 重要
让谁有动画的效果就用transition标签给包裹起来
template 中所实现的名字是固定
三个样式的类名
v-enter 进入的起点 反之对应 v-leave 离开的起点
v-enter-active 进入过程中 反之对应 v-leave-active 离开过程中
v-enter -to 进入的终点 反之对应 v-leave-to 离开的终点
v 可以替换成过度时的名字
template 加上appear属性可以使得页面在渲染时就直接呈现动画效果
app.vue
<template>
<div>
<Test/>
<Test2/>
<Test3/>
</div>
</template>
<script>
import Test from './components/Test'
import Test2 from './components/Test2'
import Test3 from './components/Test3'
export default {
name:'App',
components:{Test,Test2,Test3},
}
</script>
test.vue
动画效果页面左边缘向右出现出现,向左离开
① 基本代码
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<h1 v-show="isShow">你好啊!</h1>
</div>
</template>
<script>
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
</style>
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
/* css3知识 */
/* 使用动画 两个样式的类名 linear 匀速 reverse 反转*/
.hello-enter-active{
animation: atguigu 0.5s linear;
}
.hello-leave-active{
animation: atguigu 0.5s linear reverse;
}
/* 动画定义一个关键帧 名字可以随意 */
@keyframes atguigu {
from{
/* 来 */
transform: translateX(-100%);
}
to{
/* 来到 */
transform: translateX(0px);
}
}
</style>
实现效果类同动画(0到100%)
test2.vue —> test1.vue 的效果
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
/* 进入的起点、离开的终点 */
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
/* 来的激活时的样式,离开时激活的样式 */
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
/* 进入的终点、离开的起点 */
.hello-enter-to,.hello-leave{
transform: translateX(0);
}
</style>
错误写法一:
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
<h1 v-show="isShow">我很好谢谢!</h1>
</transition>
</div>
</template>
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<transition-group name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
<h1 v-show="isShow">我很好谢谢!</h1>
</transition-group >
</div>
</template>
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<!-- 真是列表中使用 v-for 生成 key 值-->
<transition-group name="hello" appear>
<h1 v-show="isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">我很好谢谢!</h1>
</transition-group >
</div>
</template>
正确方式二:
使用transition标签,使用div标签把两个h1标签包裹起来 但是两个展示效果不能互斥,互斥无法实现,互斥只能使用 transition-group 显示取反
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- transition 过度 appear 呈现 hello 过度时起的名字-->
<!-- 真是列表中使用 v-for 生成 key 值-->
<transition-group name="hello" appear>
<div>
<h1 v-show="isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">我很好谢谢!</h1>
</div>
</transition-group >
</div>
</template>
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition-group >
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">我很好谢谢你</h1>
</transition-group>
</div>
</template>
<script>
import 'animate.css'
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
</style>
② 使用
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- 首页中有很多样式和动画,直接左侧还有演示直接复制即可 -->
<transition-group
appear
name="animate__animated animate__bounce"
enter-active-class="animate__swing"
leave-active-class="animate__backOutUp"
>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">我很好谢谢你</h1>
</transition-group>
</div>
</template>
TodoList案例博客