JavaScript(JS 教程) - JavaScript | MDN
Vue是构建用户界面的 JavaScript 框架
- 安装 — 2.0 Vue.js
- GitHub - vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications.
- Installation | Vue Devtools
- VSCode插件:
LiveServer http://127.0.0.1:5500/ 部署整个服务 Vue 3 Snippets Vetur 设置自动保存 afterDelay - Download | Node.js
- Vue CLI
快捷键 | |
---|---|
shift+F5 | 强制刷新 |
crtl+R | 刷新控制台 |
!+ Enter | |
Alt+shfit+A | |
shift+alt+F | 格式化 |
<v + Enter | |
ctrl+shift+` | 终端 |
知识储备 | |
---|---|
ES6 | 闭包 |
webpack | ajax |
路由 | nodejs |
移动端 | JQuery |
axios | MDN 文档 |
模块化语法 | commonJS |
Promise | babel |
操作DOM | |
express koa | css less |
01_初始Vue
el元素选择为哪个容器服务
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root" class="root">
<h1>Hello,兔年2023</h1>
</div>
<script type="text/javascript">
// 创建Vue实例
const vm = new Vue({
el:'#root' //el用于指定当前Vue实例为哪个容器服务,值通常为css id选择器
el:'.root' //el用于指定当前Vue实例为哪个容器服务,值通常为css class选择器
})
</script>
</body>
</html>
定义data属性,并使用插值表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
初始Vue:
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器里的代码符合html规范,但混入了Vue语法;
3.root容器里的代码称为【Vue模板】
4.Vue实例和容器是一一对应的
5.真实开发只有一个Vue实例,并且配合着组件使用
6.{{xxx}}中的xxx要写js表达式,且xxx可以读取data中的所欲属性
7.一旦data中数据发生改变,那么模板中用到该数据的地方会自动更更新
注意区分:js表达式 和 js代码(语句)
1.表达式:一个表达式产生一个值,可以放在任何一个需要值的地方
(1). undefined
(2). a+b
(3). demo(1)
(4). x === y ? 'a':'b'
(5). vm中的数据 _xxx $xxx xxx
2.js代码(语句)
(1). if(){}
(2). for(){}
-->
<!-- 准备好一个容器 -->
<div id="root">
<h1>Hello,{{name}}</h1>
</div>
<script type="text/javascript">
// 创建Vue实例
const vm = new Vue({
el:'#root', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器
data:{ //data用于存储数据,数据供给el指定的容器使用
name:"兔年2023"
}
})
</script>
</body>
</html>
02_Vue模板语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
Vue模板语法2大类
1.插值语法:
功能:用于解析标签体内容,调用methods函数
写法:{{xxx}} 、{{xxx()}}、{{xxx.underfunded}}
来源:已存在的_data,未出现的computer计算属性,列表渲染的数组数组项,对象的underfunded属性(不会显示)
2.指令语法:
功能:用于解析标签(包含:标签属性、标签体内容、绑定事件....)
写法:v-bind:href="xxx" ,也使用js表达式
-->
<!-- 准备好一个容器 -->
<div id="root">
<h1>Hello,{{name}}</h1>
<!-- href将会发送get请求 -->
<a v-bind:href="url">点我可以去学习</a>
<!-- 简写 -->
<a :href="url">点我可以去学习</a>
</div>
<script type="text/javascript">
// 创建Vue实例
const vm = new Vue({
el:'#root', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器
data:{ //data用于存储数据,数据供给el指定的容器使用
name:'兔年2023',
url:'baidu.com'.toUpperCase()
}
})
</script>
</body>
</html>
默认的报错:
03_数据绑定
单向绑定 | 页面Input修改时只会变化容器体的内容 不关注标签体,关注标签属性 无法修改vue实例data的内容 | :<elementName>=<"JS表达式"> | |
| |||
双向模型 | 仅只支持 表单类元素(输入类元素),部分场景不可用 只关心Value,不关注KeyName 会修改vue实例data的内容 | v-model | v-model=<"JS表达式"> |
v-model.number 输入类型首次转number类型 v-model.lazy 失去焦点时收集输入内容 v-model.trim 收集输入内容时去除前后空格 | |||
样式绑定 | class不能多个,但是可以和:class配合,作为默认样式 |
:class="样式参数data" :style=”数组【styleobj1,styleobj2】“ |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
Vue有2中数据绑定方式:
1.单向绑定(v-bind):数据只能从data流向页面
2.双向绑定(v-model):数据不仅从data流向页面,还可以从页面流向data
注意:
1.双向绑定一般应用在表单类元素上操作输入value值(如:input、select等)
2.因为设计是操纵value,所以简写v-model就是收集value标签属性值
-->
<div id="root">
<h1>Hello,{{name}}</h1>
单向数据绑定<input type="text" v-bind:value="name">
单向数据绑定<input type="text" :value="name">
双向数据绑定<input type="text" v-model:value="name">
双向数据绑定<input type="text" v-model="name">
<!-- 这是错误的:v-model设计仅支持表单类元素(输入类元素上) -->
双向数据绑定<h1 v-model:value="name"></h1>
</div>
<script type="text/javascript">
// 创建Vue实例
const vm = new Vue({
el:'#root',
data:{
name:'兔年2023',
}
})
</script>
</body>
</html>
04_el与data的两种写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
data与el的2种写法
1.el的2种写法
(1)new Vue式配置el属性
(2)先创建Vue实例,再通过vm.$mount('#root')指定el的值
2.data的2种写法
(1)对象式
(2)函数式
重要原则:
由Vue管理的函数不能使用箭头函数,箭头函数this不再是Vue实例
3.data中 return上可以打印log日志查看this
-->
<div id="root">
<h1>Hello,{{name}}</h1>
</div>
<script type="text/javascript">
/* // el两种写法
const vm = new Vue({
// el:'#root', // 第一种: 直接为容器服务
data:{
name:'兔年2023',
}
})
setTimeout(() => {
vm.$mount('#root') //第二种: 间隔为容器服务
}, 1000); */
const vm = new Vue({
el:'#root',
// 第一种:对象式
/* data:{
name:'兔年2023',
} */
// 第二种: 函数式(必须返回对象,对象数据是模板需要的) 组件式必须使用
data:function (params) {
console.log("aaa",this);
return{
name:'兔年2023',
}
}
})
</script>
</body>
</html>
05_MVVM模型
<!--
MVVM模型
1.M: 模型(Model): data中的数据
2.V:视图(View): 模板代码
3.VM: 视图模型(ViewModel):Vue实例
观察发现
1.data中的所有属性,最终出现在vm实例中
2.vm实例上的所有属性 及 Vue原型所有属性,Vue模板可以直接使用
-->
06_数据代理Object.defineProperty()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<script type="text/javascript">
let number = 18
let person = {
name:'张三',
sex:'男'
}
// 可以对数据进行高级限制,属性映射
Object.defineProperty(person,'age',{
value:18 ,//value:number 不可用被枚举,不可用被修改,不可被删除
/*
enumerable:true, //控制属性 是否之后 枚举 :默认false
writable:true, //控制属性 是否之后 被修改:默认false
configurable:true //控制属性 是否之后 被删除:默认false
*/
// 当有人读取Person.age属性时,get函数(getter)被调用,且返回值就直接赋给age的值
get(){
return number
},
set(value){
console.log('Person的age值已经被修改,值是', value);
number = value; // 修改属性映射值
}
})
console.log(Object.keys(person));
console.log(person);
</script>
</body>
</html>
一、收集数据
二、数据代理
vm.data(vm.xxx代理的) = vm._data(vm.option.data.xxx配置项中的)
vm.xxx(代理数据) === vm._data.xxx(源数据)
数据劫持:_data修改,导致页面更新,vm._data = optioins.data = data 触发Getter方法
07_事件处理
1.事件的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
1.v-on:xxx 或 @xxx 绑定事件,xxx是事件名
2.事件的回调需要配置methods对象中,最总会被vm实例 或 组件实例 管理
3.事件处理的参数$event:
(1).默认不需要声明$event
(2).如果要传递其他参数,需要声明$event
4.data与methods的区别:data中的数据会被数据代理
5.绑定事件时候,可以不调用methods @xxx = yyy ,yyy是简单的函数可以用;分号分隔写多句
-->
<div id="root">
<h1>Hello,{{name}}</h1>
<button v-on:click="showInfo1">点我提示信息:一</button>
<button @click="showInfo2('arg1',$event)">点我提示信息:二</button>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'2023兔年大吉'
},
methods: {
// 传递事件对象:事件的目标 标签 和 标签体
showInfo1(event){
console.log(event);
console.log(event.target.innerText);
alert('你好啊~')
},
showInfo2(arg1,event){
console.log(arg1);
console.log(event);
console.log(event.target.innerText);
alert('你好啊~')
}
},
})
</script>
</html>
2.事件修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
*{
margin-top: 20px;
}
.demo1{
height: 50;
background-color: skyblue;
}
.box1{
padding: 5px;
background-color:orange;
}
.box2{
padding: 5px;
background-color:greenyellow;
}
.list{
height: 200px;
width: 200px;
background-color: aquamarine;
overflow: auto;
}
li{
height: 100px;
background-color: rgb(255, 0, 123);
}
</style>
</head>
<body>
<!--
Vue中事件修饰符:
1.prevent:阻止默认事件(阻止标签特性功能)
2.stop: 阻止事件冒泡
3.once: 事件回调只触发一次
4.capture: 事件捕捉模式
5.self: 只有event.taget触发者是当前操作元素才触发事件,其他元素无法触发
6.passive: 事件默认行为立即执行,无需等待回调代码块执行完毕
时间修饰符可以连续写
-->
<div id="root">
<h1>Hello,{{name}}</h1>
<a href="http://baidu.com" @click.once.prevent="showInfo">点我提示信息</a>
<!-- 事件会冒泡处理 -->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
<!--
事件捕获:用外往内捕获事件
事件冒泡:已被捕获开始由内往外触发,但event是触发者,冒泡传递时不会变。
-->
<div class="box1" @click.capture="showMsg(1)">
box1
<div class="box2" @click="showMsg(2)">box2</div>
</div>
<!-- 鼠标滚轮 和 鼠标左键 和 ↑↓键 都会触发,栏内移动就可以触发,无法再底栏触发-->
<ul class="list" @scroll="demo">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<!-- 鼠标滚轮 触发 ,底栏还可以触发-->
<ul class="list" @wheel="demo">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<!-- 默认:先执行回调函数,再执行默认行为。使用passive默认行为立即执行-->
<ul class="list" @wheel.passive="demo2">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'2023兔年大吉'
},
methods: {
showInfo(event){
alert('弹窗完可能会跳转页面')
},
showMsg(num){
console.log(num);
},
demo(){
console.log('@');
},
demo2(){
for (let index = 0; index < 100000; index++) {
console.log(index);
}
console.log('整完了');
}
},
})
</script>
</html>
事件冒泡 | 触发的事件的节点,没有处理事件的能力,并【事件函数】没有绑定在【对应事件源】,导致事件传播:规则是由里往外,绑定事件的节点都将被动触发 【div标签】中嵌套其他标签 和 内部div标签 触发 外部其他组件的 标签 冒泡,总是触发的 事件源 |
3.键盘事件
Windows实时显示键盘输入用这个小工具可以实现
keycastow-v2.0.2.5-cn
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<!--
1.键盘事件@keyup @keydown
2.@keyup.xxx 键盘别名
回车 enter
删除 delete
退出 esc
空格 space
换行 tab (特殊:必须配合keydown按下触发,且会把光标柱隐形转移走)
上 up
下 down
左 left
右 right
3.系统修饰键(特殊)ctrl alt shift meta(windos徽标键 苹果common键盘)
(1)配合keyup 按下修时键后,再按下其他键,然后释放其他键,事件才被触发
(2)配合keydown正常触发
4.keyCode可以指定具体按键
5.定制别名:Vue.config.keyCode.自定义键 = 键码,
6.别名组合键:@keyup.enter.x
-->
<div id="root">
<input type="text" placeholder="按下按键提示输入" @keydown="shouInfo1">
<input type="text" placeholder="按下按键提示输入" @keyup.enter="shouInfo2">
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'2023兔年大吉'
},
methods: {
shouInfo1(e){
if (e.keycode === 13) {
}
},
shouInfo2(e){
alert('噔噔deng!')
}
},
})
</script>
</html>
08_计算属性
联动效果(配合v-model双向绑定) | |
---|---|
methods |
|
| |
computed 计算属性 (预期插入的值: |
|
| |
watch 监视侦听 (已存在的值: |
|
| |
所有被Vue管理的函数,this是vm 或 组件实例对象,写普通函数 所有不被Vue管理的函数(timeOut定时器回调函数,ajax回调函数.Promise回调函数),用箭头函数 |
09_监控属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<!--
属性监视watch:
1.当被监视属性vm._data变化时,回调函数自动调用,并进行相关操作
2.监视的属性必须存在
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
4.不需要"监测项"时可以简写
5.监控项 immediate:true 首次主动监听触发
深度监视(vm_data.xxx.yyy.zzz 细粒度)
vue会深度检测到变化,但watch深度属性改变不会被检测到.除非xxx被重新赋值则视为改变
-->
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="changeWeather">点我修改天气</button>
<button @click="number.a++">点我修改a自增1</button>
<h1>{{number.a}}</h1>
<h1>{{number.b}}</h1>
<button @click="number= {a:111 }">点我修改number</button>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
isHost: false,
number:{
a:1,
b:2
}
},
methods: {
changeWeather(){
this.isHost = !this.isHost
}
},
computed: {
info(){
return this.isHost ? '炎热' :'寒冷'
}
},
/* watch: {
isHost:{
// 初始化时让Handler调用一下
immediate:true,
// handler调用实际,当_data数据被修改时触发
handler(newValue,oldValue){
console.log('isHost被修改了',newValue+ '<-' +oldValue);
}
}
}, */
watch: {
/* number:{
// 初始化时让Handler调用一下
immediate:true,
deep:true,
// handler调用实际,当_data数据被修改时触发
handler(newValue,oldValue){
console.log('number被修改了',newValue+ '<-' +oldValue);
}
},
"number.a":{
// 初始化时让Handler调用一下
immediate:true,
// handler调用实际,当_data数据被修改时触发
handler(newValue,oldValue){
console.log('number.a被修改了',newValue+ '<-' +oldValue);
}
} */
// 简写:
number(newValue,oldValue){
console.log('number被修改了',newValue+ '<-' +oldValue);
}
},
})
// 创建完实例后进行监视写法
/* vm.$watch('isHost',{
handler(newValue,oldValue){
console.log('isHost被修改了',newValue+ '<-' +oldValue);
}
}) */
vm.$watch('isHost',function (newValue,oldValue) {
console.log('isHost被修改了',newValue+ '<-' +oldValue);
})
</script>
</html>
10_绑定样式
容器可以设置多个绑定器(一对多)
1.绑定class样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
.basic{
background-color: aqua;
}
.normal{
height: 200px;
width: 200px;
}
.happy1{
background-color: rgb(183, 16, 16);
height: 400px;
width: 400px;
}
.happy2{
background-color: yellow;
height: 400px;
width: 400px;
}
.happy3{
background-color: green;
height: 400px;
width: 400px;
}
</style>
</head>
<body>
<div id="root">
<!-- 字符串写法:样式的类名动态决定 -->
<div class="basic" :class="mood" @click="changeMood">
这个盒子点击会修改样式
</div>
<!-- 数组写法(一) 样式个数不确定,类名不确定,通过数组函数shift操作-->
<div class="basic" :class="classArr" @click="changeMood">
这个盒子点击会修改样式
</div>
<!-- 数组写法(二) -->
<div class="basic" :class="['happy1','happy2','happy3']" @click="changeMood">
这个盒子点击会修改样式
</div>
<!-- 对象写法: 样式确定,类名确定,组合动态决定:通过Vue工具操作-->
<div class="basic" :class="classObj" @click="changeMood">
这个盒子点击会修改样式
</div>
<!-- 对象写法-->
<div class="basic" :class="{ happy1:false,happy2:false}" @click="changeMood">
这个盒子点击会修改样式
</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
mood:'normal',
classArr:['happy1','happy2','happy3'],
classObj:{
happy1:false,
happy2:false,
happy3:false,
}
},
methods: {
changeMood(){
const arr = ['happy1','happy2','happy3']
const index = Math.floor(Math.random()*3)
this.mood = arr [index]
}
}
})
</script>
</html>
2.Style内联样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
.basic{
background-color: aqua;
}
.normal{
height: 200px;
width: 200px;
}
.happy1{
background-color: rgb(183, 16, 16);
height: 400px;
width: 400px;
}
.happy2{
background-color: yellow;
height: 400px;
width: 400px;
}
.happy3{
background-color: green;
height: 400px;
width: 400px;
}
</style>
</head>
<body>
<div id="root">
<!-- 字符串写法:样式的类名动态决定 -->
<div class="basic" :style="{fontSize: fsize+'px'}">
这个盒子点击会修改样式
</div>
<!-- 对象写法 -->
<div class="basic" :style="styleObj1">
这个盒子点击会修改样式
</div>
<!-- 数组写法 -->
<div class="basic" :style="[styleObj1,styleObj2]">
这个盒子点击会修改样式
</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
fsize:40,
styleObj1:{
fontSzie:'40px',
color:'red',
},
styleObj2:{
backgroundColor:'blue'
}
}
})
</script>
</html>
11_条件渲染
不能配合Template标签使用
| 修改频率高 | |||||||
一组使用 |
可以配合Template标签使用: 此标签将【一些结点】临时当作【一个结点】判断是否显示 | |||||||
判断是根据boolean值 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
<button @click="isShow=!isShow">点我隐藏文字</button>
<h1 v-show="isShow">条件渲染</h1>
<button @click="n++">点我会按条件展示盒子</button>
<button @click="n--">点我会按条件展示盒子</button>
<!-- 一组使用 -->
<div v-if="n === 1">1</div>
<div v-else-if="n === 2">2</div>
<div v-else>3</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
isShow:false,
n:1
}
})
</script>
</html>
12_列表渲染
1.列表展示
遍历对象数组 | v-for='数据p in或者of 数据池' :key='p.id或index' 对象可能有相同的,但是最好有Id v-for='(数据p,索引index) in或者of 数据池' 注意:列表渲染关注数组的key,必须指定标识,标识是对象的唯一标识,不要使用index 实际开发:id由服务器进行维护 key用于递步算法 |
遍历对象 | v-for='value,key.... in或者of 对象' 注意:key与value顺序不同 |
遍历字符串 | v-for='(字符,索引)' in或者of 字符串' |
遍历指定次数 | v-for='(数值,索引)' in或者of 数字' 数值从1开始 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<!--
列表渲染:
1.遍历时的两个参数
(1)数组:(对象,index)
(2)对象:(value,key)
(3)字符串:(char,charIndex)
(4)指定次数:(1开始数值,数值索引)
2.关键词 in 或 of
-->
<div id="root">
<!-- 遍历数组 -->
<h1>人员列表</h1>
<ul>
<li v-for="p in persons" :key="p.id">
{{p.name}} - {{p.age}}
</li>
</ul>
<ul>
<li v-for="(p,index) of persons" :key="p.id">
{{p.name}} - {{p.age}} - {{index}}
</li>
</ul>
<!-- 遍历对象 -->
<ul>
<li v-for="(item, index) in car">
{{item}} - {{index}}
</li>
</ul>
<!-- 遍历字符串 -->
<ul>
<li v-for="(item, index) in str" :key="index">
{{item}} - {{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<ul>
<li v-for="(item, index) in 5" :key="index">
{{item}} - {{index}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:'18'},
{id:'002',name:'李四',age:'19'},
{id:'003',name:'王五',age:'28'},
],
car:{
name:'奥迪A8',
price:'70万',
color:'银色'
},
str:'helloWorld'
}
})
</script>
</html>
错乱:渲染时虚拟Dom对比已存在Id将复用,Index不指定造成错乱,需要唯一标识符 |
diff算法 |
面试题:react、vue中的key有声明作用?
key的内部原理:
1.虚拟Dom中Key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】
随后Vue进行【新的虚拟DOM】与【旧的虚拟DOM】差异比对,比对规则如下:
2.比对规则
(1)【旧的虚拟DOM】中内容找到与【新的虚拟DOM】相同的key
对比内容没有变化,直接使用【旧的真实DOM】
对比内容变化,创建【新的真实DOM】,替换【旧的虚拟DOM】
(2)【旧的虚拟DOM】中内容没有找到与【新的虚拟DOM】相同的key
创建【新的真实DOM】,随后渲染到页面
3.用index作为key可能引发的问题:
(1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的【旧的真实DOM】更新 = > 效果没有问题,但无法diff算法复用效率低
(2)结构中包含输入类DOM
产生错误DOM更新 = > 界面有问题
4.如何选择key?
(1) 每条数据使用唯一标识符,id、手机号、身份证号码、学号
(2) 如果不存在破坏顺序操作,仅用于渲染展示,使用index作为key没有问题
2.列表过滤
watch | |
computer | |
3.列表排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
<!-- 遍历数组 -->
<h1>人员列表</h1>
<input type="text" v-model="keyWord" >
<button @click="sortType=0">正序</button>
<button @click="sortType=1">降序</button>
<button @click="sortType=2">原顺序</button>
<ul>
<li v-for="fp in filePersons" :key="fp.id">
{{fp.name}} - {{fp.age}} <input type="text">
</li>
</ul>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:'20'},
{id:'002',name:'李四',age:'19'},
{id:'003',name:'王五',age:'28'},
],
keyWord:'',
sortType:2
},
computed: {
filePersons(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) !== -1
})
if(this.sortType){
return arr.sort((p1,p2)=>{
return this.sortType === 1 ? p1.age - p2.age : p2.age - p1.age
})
}
return this.persons
}
},
})
let arr = [1]
</script>
</html>
4.Vue检测数据——对象原理
Vue工具更新时问题,内存数据已经发生变化,但页面不变化Vue无法检测到,Vue不承认改变。
构造函数:Observer监视者
检测data的变化,请查阅06_数据代理
_data转数组,遍历数组通过definePropetry给Observer添加此数组元素,将为每个新添加响应式 reactiveSet 和 reactiveGet
当页面获取元素时,通过Observer 响应式 getter函数 赋值给data:vm._data -> obs -> data
响应后数据同步 vm._data === data ;经过此设计,修改data则触发obs.set方法修改vm._data
5.Vue检测数据——后续添加响应式
构造参数已经生成影影视,后添加的属性无响应式的
针对对象属性
(一) 通过Vue
(二)通过vm
(三)通过Observer修改
tagert不允许是 vm 和 vm._data 直接添加属性一级对象
只能添加二级对象 vm.xxx 和 vm._data.yyy
6.Vue检测数据——数组类型
数组:不能通过Setter 和 Getter响应式检测(无响应式)
但通过影响源数组的函数(push pop shift unshift splice sort reverse)Vue会响应式
或使用
没有被Vue管理的arr
被Vue管理的arr(重载原型方法 1.调用原型 2.重写解析模板)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<!--
Vue监视数据的原理:
1.vue监视data中所有层次数据
2.如何检测对象中的数据?
通过setter实现检测,new Vue时生成响应式
3.如何检测数组的数据?
通过包裹数组更新元素的方法实现,做了两件事
(1).调用原生对应方法对数组更新
(2).重新解析模板,进而更新页面
-->
<div id="root">
<button @click="age++">年龄+1</button>
<button @click="addSex">添加性别属性:默认:男</button>
<button @click="updateSex">修改性别属性:默认:女</button>
<button @click="addFriend">列表首位添加一个朋友</button>
<button @click="friends[0].name='张三'">修改首位添加一个朋友名名字为:张三</button>
<button @click="addHobby">添加一个爱好</button>
<button @click="updateHobby">修改首个爱好:开车</button>
<h3>姓名</h3>
{{name}}
<h3>年龄</h3>
{{age}}
<h3 v-if="student.sex">性别</h3>
{{student.sex}}
<h3>爱好</h3>
<ul><li v-for="(item, index) in hobby" :key="index">
{{item}}
</li></ul>
<h3>朋友</h3>
<ul><li v-for="(item, index) in friends" :key="index">
{{item.name}} - {{item.age}}
</li></ul>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
student:{
},
name:'tom',
age:'18',
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:35},
{name:'tony',age:55}
]
},
methods: {
addSex(){
vm.$set(this.student,'sex','男')
},
updateSex(){
this.$set(this.student,'sex','女')
},
addFriend(){
this.friends.unshift({name:'mark',age:95})
},
updateFriend(){},
addHobby(){
this.hobby.unshift('溜冰')
},
updateHobby(){
this.hobby.splice(0,1,'开车')
}
},
})
</script>
</html>
13_收集form表单数据
v-submit
// 转Json,不建议访问_data,建议使用一级属性包装
<input type="number" v-model.number="age">
v-model.number 输入类型首次转number类型
v-model.lazy 失去焦点时收集输入内容
v-model.trim 收集输入内容时去除前后空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="account"> <p></p>
密码:<input type="password" v-model.number="password"> <p></p>
年龄:<input type="number" v-model.number="age">
性别:
男<input type="radio" name="sex" value="male" v-model="sex">
女<input type="radio" name="sex" value="female" v-model="sex"><p></p>
爱好:
学习<input v-model="hobby" type="checkbox" value="study">
游戏<input v-model="hobby" type="checkbox" value="game">
美食<input v-model="hobby" type="checkbox" value="eat"> <p></p>
所属地:
<select v-model="city">
<option value="">-----请选择地址------</option>
<option value="">中国</option>
<option value="">美国</option>
<option value="">日本</option>
</select><p></p>
补充:
<textarea cols="30" rows="10" v-model.lazy="other"></textarea><p></p>
<input type="checkbox" v-model="isTure">我已阅读<a href="">详情协议</a><p></p>
<!-- 点击按钮会触发事件 -->
<button>提交</button>
</form>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
account:'',
password:'',
sex:'',
hobby:[],
city:'',
other:'',
isTure:'',
},methods: {
demo(){
alert("兔年2023牛逼")
// 转Json,不建议访问_data,建议使用一级属性包装
alert(JSON.stringify(this._data))
}
},
})
</script>
</html>
14_过滤器filters
BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务
用于格式化时间戳:离线下载js包
<!-- 引入dayjs -->
<script type="text/javascript" src="../js/dayjs.min.js"></script>
filters | 适合串联处理,可以传递指定返回值作为参数连续传递 局部过滤器 全局过滤器 |
管道符 | :默认传递第一个参数不需要管道后声明,其他参数需要声明 支持{{}}插值表达式 支持v-bind修改标签属性 |
1.过滤器的串联 (局部过滤器)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="../js/dayjs.min.js"></script>
<style>
</style>
</head>
<body>
<div id="root">
时间戳:{{timeStamp}}
<!-- 计算属性实现 -->
<h2>计算属性实现格式化后时间:{{timeFormat}}</h2>
<!-- method实现 -->
<h2 >method实现格式化后时间:{{timeFmt()}}</h2>
<!-- 过滤器实现 -->
<h2 >过滤器实现格式化后时间:{{timeStamp | timeFormater()}}</h2>
<!-- 传递参数 -->
<h2 >过滤器实现格式化后时间:{{timeStamp | timeFormater('YYYY_MM_DD') | mySlice}}</h2>
</div>
<div id="root2">
<!-- 使用全局过滤器 -->
<h2 >过滤器实现格式化后时间:{{showStr | GlobalSlice}}</h2>
</div>
<div id="root3">
<!-- v-bind使用全局过滤器 -->
<h2 :x="xStr | GlobalSlice">这里的被绑定属性 并使用了过滤器</h2>
</div>
</body>
<script type="text/javascript">
let timeNow = Date.now()
// 注册全局过滤器: 著能一个一个注册,适合组件复用,可以服务不同的容器
Vue.filter('GlobalSlice', function (value) {
return value.slice(3,14)
})
const vm = new Vue({
el:'#root',
data:{
timeStamp:timeNow,
},
methods: {
timeFmt(){
return dayjs(this.timeStamp).format('YYYY-MM-DD HH:mm:ss')
}
},
computed: {
timeFormat(){
return dayjs(this.timeStamp).format('YYYY-MM-DD HH:mm:ss')
}
},
filters:{
// ES6 默认参数
timeFormater(value,str='YYYY年MM月DD日'){
return dayjs(value).format(str)
},
mySlice(value){
return value.slice(0,7)
}
}
})
new Vue({
el:'#root2',
data:{
showStr:'...helloWorld!!!'
}
})
new Vue({
el:'#root3',
data:{
xStr:'...helloWorld!!!'
}
})
</script>
</html>
15_内置指令
v-text | 将vm._data.xxx 作为【字符串】直接替换【节点内容】,且不渲染html标签 |
v-html | 将vm._data.xxx 作为【字符串/HTML结构】替换【节点内容】 冒充用户之手:虚拟身份Cookies访问浏览器(存在硬盘) XSS攻击:携带Cookies跳转(部分服务器健全JS脚本无法获取,参数需要Http协议) |
v-cloak | 页面闪现:JS引入的时间存在网络抖动阻塞页面渲染,导致一瞬间被解析。适合网速慢时未经解析的模板不展现。 |
v-once | 将vm._data.xxx 页面初始化时替换【模板的插值表达式】一次动态渲染后 静态渲染:此模板标签首次后将不依赖data随后的变化 注意:【v-once指令】 与 【v-on.once事件修饰符】不同 |
v-pre | 加速模板:跳过此节点的编译过程,适用于模板中未使用【插值语法】和【指令语法】 |
16_自定义指令
自定义指令 | 拦截功能:在部分执行时机调用对象函数 触发时机函数: 1、指令与元素绑定时,模板初次渲染 2、模板其他数值发生变化触发渲染,diff比对 注意: 1.指令与元素绑定时,模板还没有放入页面 2.指令中回调函数中this是winedow 3、对象风格函数,插入页面时触发 指令命名规则:多单词时kube-case命名风格,不能使用camelCase 全局自定义指令:和filters类似 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内置指令</title>
<style>
</style>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--
v-big: 和v-text功能类似,但将数值增加10倍
v-fbind: 和v-bind功能类似,但input位置可以获取焦点,属性 autofocus可以 input.focus()
-->
<div id="root">
<h2>当前num值是 <span v-text="num"></span></h2>
<h2>放大10倍后num值是 <span v-big="num"></span></h2>
<button @click="num++">点我num++</button><p></p>
<input type="text" autofocus><p></p>
<input type="text" v-fbind:value="num">
</div>
</body>
<script type="text/javascript">
// 全局自定义,写法一 【对象式】
Vue.directive('newBind1', {
// 指令与元素绑定时
bind(element,binding){
element.value = binding.value
},
// 指令插入页面时
inserted(element,binding){
element.focus()
},
// 指令被触发重新解析时
update(element,binding){
element.value = binding.value
}
})
// 全局自定义,写法二 【函数式】
Vue.directive('newBind', function(element,binding){
element.innerText = binding.value * 10
console.dir(element)
console.dir(binding)
})
const vm = new Vue({
el:'#root',
data:{
num:99
},
directives:{
// 写法一 【对象式】: 适合细节,可以做拦截执行,额外执行inserted
fbind:{
// 指令与元素绑定时
bind(element,binding){
element.value = binding.value
},
// 指令插入页面时
inserted(element,binding){
element.focus()
},
// 指令被触发重新解析时
update(element,binding){
element.value = binding.value
}
},
// 写法二 【函数式】: 简单,但无法做拦截操作。只执行 bind 和 update
big(element,binding){
element.innerText = binding.value * 10
console.dir(element)
console.dir(binding)
}
}
})
</script>
</html>
16_生命周期(生命周期钩子回调函数)
自定义指令的触发时机回调函数 | this指向的是windows |
生命周期中的回调函数 | this指向的是vm 或 组件实例 |
0.引入代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内置指令</title>
<style>
</style>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 绑定内敛样式:调节透明度 -->
<div id="root">
<h2 :style="{opacity: opacity}">欢迎来到2023兔年</h2>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
opacity:1
},
// Vue完成模板解析 -> 初始的真实DOM插入后面后(挂载完毕) -> 调用mounted
mounted() {
setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) {
this.opacity = 1
}
}, 16);
},
})
</script>
</html>
挂载流程 | beforeCreate (未做数据代理) 1.事件刚开始,不能访问到_data 和 methods created (数据代理) 1.getter 和 setter 以及 methods (生成虚拟DOM到内存中) 1.实例化时已指定vm是否指定为哪个容器模板服务(配置el);如果没有指定将不执行后续钩子,等待手动执行指定vm.$mount('root')后执行其他生命周期钩子 2.如果配置template配置项,value使用``反引号的内容直接替换【服务的容器】,成为新的服务容器。(不允许有两个根节点,可以用一个容器节点封装) 注意:【template配置项】与【<template>标签】不同 3.服务的模板是 内部定义的模板 或 template配置项替换的模板 beforeMount (页面呈现:未经编译DOM结构) 1.备份虚拟DOM:vm$el (用于更新流程:复用DOM) 2.将虚拟DOM 转为 真实DOM 插入页面 注意:此钩子操作的DOM,最终不奏效。因为会直接使用created生成的虚拟DOM替换 mounted(页面呈现:编译DOM结构) 1.挂在完毕,进行初始化操作:开启定时器setnterval、发送网络请求、订阅消息、绑定自定义事件 |
更新流程 (数据改动时被动触发) | beforeUpdate:(页面呈现:旧数据) 1.页面尚未同步新的数据,但数据已经变化 (【新虚拟DOM】与【旧虚拟DOM】比较) 1.比较 2.进行页面的更新,既:完成 MVVM: Model -> View upodated :(页面呈现:新数据) 1.数据和页面保持同步 |
销毁流程 (可以主动触发) | vm.$destroy 函数被调用 ,并清理它与其他实例(组件实例)的连接,解绑全部指令及事件监听器(自定义事件),但不解绑原生自定义DOM事件 beforeDestory(数据处于最后可用状态) 1.收尾操作,马上执行销毁,但对数据的所有操作都不会在执行【更新流程】。 2.此时会关闭定时器clearInterval(this.timer)、取消订阅消息、绑定自定义事件 收尾操作,可用修改数据,但不会调用Update更新 移除所有watchs,component,evnet listner destoryed (彻底销毁) |
路由钩子(三个) |
17_组件化
模块化(原生JS) | 组件化(VueJS) |
---|---|
耦合性:横向引用,纵向引用 多引用:引用关系复杂,三剑客分开过细 螺丝 螺母 螺丝刀 | 耦合性:依然存在,但作为一套避免了横向引用 片段化:CSS + HTML片段 + JS,封装为一套 一块砖 |
组件的定义: 实现界面局部功能代码和资源的集合 组件必须被vm (Root)管理 命名规则: 1.可以定义为大写 和 原生代码区分,避免和原生相似 2.kube-case写法 3.AxxxBxxx 写法(需要使用vue-cli脚手架) 4.通过配置项name组件标签在Vue工具呈现的名字 自闭合标签; 1.需要使用脚手架 组件嵌套 1.注册给谁,在哪个模板里面调用组件标签 APP组件(管理) 1.app组件管理其他全部组件 |
1.非单文件组件(单文件包含n个组件:无插件提示):
函数式 data | 对象式 data |
---|---|
所有组件共享一个data对象 | 每个组件独享新的data对象 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内置指令</title>
<style>
</style>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<!-- (三)编写组件标签 -->
</div>
<div id="root2">
<!-- (三)编写组件标签 -->
<room></room>
</div>
</body>
<script type="text/javascript">
// (一)创建组件:注意组件一定要先创建
const student = Vue.extend({
template:
`<div>
<h1>{{studentName}}</h1>
</div>`,
data() {
return {
studentName: '兔子哥'
}
},
})
const school = Vue.extend({
template:
`<div>
<student></student>
<h1>{{schoolName}}</h1>
</div>`,
data() {
return {
schoolName: '清华大学'
}
},
components: {
student
}
})
const App = Vue.extend({
template:
`<div>
<school></school>
</div>`,
components: {
school
}
})
new Vue({
template:`<div>
<App></App>
</div>`,
el: '#root',
// (二)注册组件:局部注册
components: {
// 简写:相同可以简写
App: App,
}
})
// (一)创建组件:简写形式 ,被VueJS源码帮助执行
const room = {
template:
`<div>
<h1>{{dogName}}</h1>
</div>`,
data() {
return {
dogName: '柴犬'
}
},
}
// (二)注册组件:全局注册
Vue.component('room', room)
new Vue({
el: '#root2'
})
</script>
</html>
2.组件实例的构造函数VueComponent()
组件中this【vc】 | VueComponent实例对象(底层是函数式的构造函数每次【组件独立】) 不能服务el容器 data必须函数式 |
newVue()中this【vm】 | Vue实例对象 可以服务el容器 data写法可以 vm $children组件管理组件 |
3.Vue与VueComponent内置关系(原型对象)
实例对象 | 构造函数 |
隐式原型属性 === 显示原型属性 (是一块内存) Vue构造函数(不存在) > 显示原型链(寻找) > 原型对象 > 隐式原型链(寻找)> Object原型对象 vm实例 > 隐式原型链(寻找)> 原型对象 > Object VueComponent构造函数(不存在) > 显示原型链(寻找) > VueComponent原型对象 > 隐式原型链(寻找)> Vue原型对象 vc实例 > 隐式原型链(寻找)> VueComponent原型对象 > Vue 通过原型链:类似于【Java类的继承】,但实例可以添加参数给原型对象,复用部分函数和数据 |
4.单文件组件(单文件包含单个组件):
ES6技术模块化【暴露expose】与【导入import】 技术 | |||
---|---|---|---|
组件依赖 | |||
分别暴露 | 导入 | | |
统一暴露 | |||
默认暴露 | |||
| |||
<template></template>模板必须使用【根元素】 【模板标签<template></template>】 = 【模板配置项template:`<App></App>`】 |
规范化需要:JS的入口 【main.js】,以下操作依赖脚手架
Vuc CLI 脚手架
1.分析Vuc CLI 脚手架 (conmmand line interface)
CLI安装:依赖【Node.js环境】 | 设置国内npm淘宝镜像 |
angular cli - npm ERR! Invalid response body while trying to fetch http://registry.npmjs.org/accepts: Integrity verification failed for sha - Stack Overflow | |
javascript - npm WARN enoent ENOENT: no such file or directory, open 'C:\Users\Nuwanst\package.json' - Stack Overflow | |
Vue命令 | 指定创建项目的目录-会创建自带例子demo vue create 运行此目录的服务 npm run serve |
文件介绍:
注意:
1.VsCode每个修改一个文件都需要单独Ctrl+S保存,否则不生效。或设置自动保存
2.关闭代码检测
【index.html】被服务的容器,被展示的页面
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<!-- 针对IE浏览器:以最高渲染级别渲染 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 开启移动端的理想视口 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- JSP配置页签:引入路径 -->
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- JSP配置网页的标题 -->
<title><%= htmlWebpackPlugin.options.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>
【main.js】 项目npm运行的入口
/*
该文件是整个项目的入口文件
*/
// 1.引入Vue
import Vue from 'vue'
// 2.引入App组件
import App from './App.vue'
// 3.关闭vue的生产提示
Vue.config.productionTip = false
// 4.创建Vue实例(vm),指定服务的容器 和 使用reader函数将App组件编译
new Vue({
render: h => h(App),
}).$mount('#app')
【App.vue】
<template>
<!-- 3.定义顶级标签:编辑模板内容,使用【子组件】 -->
<div>
<Student name="张三" age="18" sex="女"/>
</div>
</template>
<script>
// 1.导入 【子组件】
import Student from './components/Student.vue'
// 2.定义 【暴露的组件名称】,并注册 【子组件】
export default {
name:'App',
components:{
Student
}
}
</script>
【assets】静态文件夹
【components】组件文件夹,不包含App.vue
【.gitignore】忽略Git Commit的文件
【babel.config.js】babel转换标准
【package-lock】npm配置项的锁定值
【package】npm项目包的说明书(webpack命令 = maven指令)
【README.md】Git展示文件
【vue.config.js】记得编写时关闭于法检测
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false
})
2.运行时版本Vue的render函数
CLI编译后使用版本
完整版vue.js
由于未使用完整版vue.js,使用的是vue.runtim.xxx.js精简版,节省解析器1/3内存,所以无法直接使用template配置项,需要使用脚手架render函数
【render函数】:帮助渲染template配置项,将import导入式模块化 .vue 编译为浏览器解析的 .js
3.修改Cli默认配置
打印默认配置 | 选择合适的目录,管理员身份运行 vue inspect > output.js |
修改 | vue.config.js |
语法检查 | lint |
Configuration Reference | Vue CLI
注意:默认开启代码检查lintOnSave,如:变量没有使用
4.ref属性获取DOM
原生 id 属性 | Vue ref属性 | |
HTML标签 | | |
组件标签 | 获取模板中DOM结构 | 获取组件实例对象VC |
<template>
<!--
ref属性;
1.被用来给【元素】或 【子组件】注册应用信息(原生id属性的替代品)
2.html标签获取真实DOM元素,组件标签上获取组件实例对象(vc)
-->
<div>
<!--
1.打标识
-->
<School ref="sch" id="sch"/>
<h1 v-text="msg" ref="title" ></h1>
<button @click="showDOM" >点我输出上方DOM元素</button>
</div>
</template>
<script>
import School from './components/School.vue'
export default {
name:'App',
data() {
return {
msg:'我爱学习'
}
},
methods: {
showDOM(){
console.log(this.$refs.title);
console.log(this.$refs.sch);
console.log(document.getElementById('sch'));
}
},
components:{
School
}
}
</script>
5.配置项props:data的 传参 和 入参
引用组件时传参
<div>
<Student name="张三" age="18" sex="女"/>
</div>
注意:传参后对Number类型做四则运算,需要限制
简单接收(需要间接解决) | 限制传参(直接解决) |
---|---|
| 简写 |
1.入参时,使用*法,不要先使用+法会当作字符串拼接 2.传参时,使用v-bind按照表达式处理的返回结果 | 完全 |
// 类型限制
|
通过时间修改props中prop内容,Vue不推荐直接操作
间接操作prop内容
<template>
<div class="school">
<h1>{{msg}}</h1>
<h1>学生姓名: {{eventName}} </h1>
<h1>学生性别: {{sex}}</h1>
<h1>学生年龄: {{age}}</h1>
<button @click="changeName">点我名字变为:王五</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
console.log(this);
return {
msg:'我是一个好人',
eventName:this.name
}
},
methods: {
changeName(){
this.eventName = '王五'
}
},
props:{
name:{
type:String,
required:true
},
sex:{
type:String,
required:true
},
age:{
type:Number,
default:99 //默认值
}
}
}
</script>
6.配置项mixins:混合
多个组件VC中的所有相同的配置项 和 生命周期钩子,抽出为【mixin.js】文件
1. 与其他配置项混合使用,若已存在相同名称,则不混合,不会造成冲突
2. 若存在相同【生命周期钩子函数】,则将其代码合并,全部执行(混合先执行)
【mixin.js】设计混合的内容
// 定义混合的配置项,并分别暴露
export const mixinObj = {
methods: {
showName(){
alert(this.name)
}
}
}
局部混合
可以指定单个组件vc混入其内容
注意:模板应用混合的配置项,名称要保持相同
全局混合
【main.js】中引入分别暴露,vm和所有vc的组件都会混合到其内容
import Vue from 'vue'
import App from './App.vue'
// 1.引用混合
import { mixinObj,mixinObj2 } from "./maxin";
Vue.config.productionTip='false'
// 2.注册给Vue
Vue.mixin(mixinObj)
Vue.mixin(mixinObj2)
new Vue({
el:'#app',
render:h=>h(App)
})
7.插件plugins
定义插件:必须定义install方法,可以获取Vue缔造者,设计全局配置项 和 方法
export default {
// 定义插件:获取Vue缔造者,并且可以获取参数
install(Vue,arg1...){
// 定义:全局过滤器
Vue.filters('mySlice',function(value){
return value.slice(0,4)
})
// 定义:全局指令
Vue.directives('fbind'{
bind(element,binding){
element.value = binding.value
},
inserted(element,binding){
element.focus
},
update(element,binding){
element.value = binding.value
}
})
// 定义:全局混入
Vue.mixins({
data() {
return {
x:66,
y:77
}
},
})
// 定义:Vue原型上添加一个方法(vm和vc都能用)
Vue.prototype.demo = ()=>{alert('你好弹窗')}
}
}
使用插件: 在需要使用的组件引入,直接调用即可
// 引入插件
import plugins from './plugins'
// 应用插件
Vue.use(plugins)
Vue.use(plugins1)
Vue.use(plugins2)
8. style标签属性scoped
1.App中的样式将会覆盖所有的子组件
2.【后引入组件】的样式将会覆盖【先引入组件】
3.webpage Vue5.0支持 less写法 styleLang,默认css
4.npm view webpack/less-loader viersion 查询最新的所有版本
5.npm i less-loader@7 指定版本
6. 安装style插件
7.less写法嵌套样式