指令
指令是Directives,是模板语法,用于辅助开发渲染页面的基本结构
1.内容渲染指令
v-text
<p v-text='username'></p>
const vm=new Vue({
el:'app',
data:{
username:'zhangsan'
}
})
缺点:会把标签内原有的内容覆盖调
插值语法{{}},用来解决text覆盖原有内容问题,除了可以插值还可以进行一些js里面的运算
<p >{{username}}</p>
const vm=new Vue({
el:'app',
data:{
username:'zhangsan'
}
})
v-html可以渲染带标签的字符串到页面中
2.属性绑定指令
v-bind:/:为元素属性动态绑定值还可以进行一些js里面的运算
input :placeholder="a+b"/"'gh'+b"/"username"
const vm=new Vue({
el:'app',
data:{
username:'zhangsan',
a:1,
b:2,
}
})
3.事件绑定指令
v-on事件绑定指令简写@click
<button v-on:click="add">提交</button>
el:'#app'
data:{
},
methods:{
add(){
cl(1)
}
}
$.event原生的dom对象e
<button @click="add(0,$event)">
事件修饰符
.prevent消除默认事件@click.prevent
事件修饰符 | 说明 |
---|---|
.prevent | 阻止默认行为 |
.stop | 阻止事件冒泡 |
.capture | 以捕获模式触发当前的事件处理函数 |
.once | 绑定的事件只触发一次 |
.self | 只有在event.target是当前元素的自身触发事件处理函数 |
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
.passive
修饰符一般用于触摸事件的监听器,可以用来改善移动端的滚屏性能
按键修饰符
@click.esc
摁返回键触发
@keyup.enter
向下键触发
<input @keyup.page-down="onPageDown" />
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
系统按键修饰符
.ctrl
.alt
.shift
.meta
系统按键修饰符
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>
.exact修饰符
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
鼠标按键
.left
.right
.middle
4.双向绑定指令v-model
下面这段就等价于v-model
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
可以让程序员在不操作dom的情况下读取和修改data中的值
v-model修饰符
.lazy input输入完之后失去焦点才更新数据
.number 输入之后如果值是数字就转成number类型,是文字就原封不动
.trim自动去除空格
<input v-model.trim="msg" />
5.条件渲染指令
v-if
v-else
v-else-if
v-show
当这几个元素的值为true时被绑定元素内的内容从才会被显示
v-if和v-show的区别
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display
属性会被切换。
总的来说,v-if操作dom元素的销毁于重建,v-show操作dom元素的显示与隐藏,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if
会更合适。
6.列表渲染指令v-for
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../js-vue/vue.js"></script>
<!-- <script src="../vuejs/antd.min.js"></script>
<link rel="stylesheet" href="../vuejs/antd.min.css" /> -->
</head>
<body>
<div id="app">
<input type="search" value="" @keyup.esc="clearn" />
<input v-model.lazy="searchText" />
<input type="text" name="" id="" v-model.number="checkbox" />
<h1 v-if="checkbox">11s</h1>
<h1 v-else>else</h1>
<!-- v-for -->
<h1 v-for="(item,index) in dataBase">
{{item.name}}-{{index}}-{{item.age?item.age:"未填写"}}-{{item.sex}}
</h1>
<!-- v-for 对象解构写法-->
<h1 v-for="({name,age,sex},index) in dataBase">
{{name}}-{{index}}-{{age?age:"未填写"}}-{{sex}}
</h1>
<!-- 对于多层嵌套的 v-for,作用域的工作方式和函数的作用域很类似。每个 v-for 作用域都可以访问到父级作用域: -->
<div v-for="({name,age,sex},index) in dataBase">
<!--也可以使用of代替in更符合js迭代-->
<span v-for="item in jg">{{name}}-{{item}}</span>
</div>
<!-- 你也可以使用 v-for 来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。 -->
<div v-for="(key,value,index) in searchText">
{{index}}-{{key}}:{{value}}
</div>
<!-- 直接接受一个整数值。1...n 的取值范围重复多次。从1-15包括1和 15-->
<p v-for="n in 15">{{n}}</p>
<!-- tem 可以在 <template> 标签上使用 v-for 来渲染一个包含多个元素的块。-->
<ul>
<template v-for="item in dataBase">
<li>{{ item.name }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
searchText: {
name: 'nihao1',
area: '云南',
},
checkbox: 0,
jg: [1, 2, 3, 4, 5],
dataBase: [
{
name: 'zs',
sex: '男',
},
{
name: 'ls',
sex: '男',
},
{
name: 'lt',
sex: '男',
age: 25,
},
],
},
methods: {
clearn(e) {
console.log('触发了按键修饰符');
e.target.value = '';
},
},
});
</script>
</body>
</html>
同时使用 v-if
和 v-for
是不推荐的,因为这样二者的优先级不明显。
在外新包装一层 <template>
再在其上使用 v-for
可以解决这个问题 (这也更加明显易读):
<template v-for="item in dataBase">
<li v-if="item.age">{{ item.name }}</li>
<li class="divider" role="presentation"></li>
</template>
绑定Key管理vue的dom的状态:
Vue 默认按照“就地更新”的策略来更新通过 v-for
渲染的元素列表。确保他们在原本指定的位置进行渲染。
为了便于vue跟踪节点的标识,从而重新、重用对现有的元素排序,需要给对应元素加一个唯一的key属性。key是通过v-bind绑定的一个特殊的属性而不是item中的那个key属性。
值一般是一个number类型,一般用item.id。
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
key值需要是一个唯一值,不能以index当作key的值,因为没有强制的绑定方式,也不能说是个严谨的值。
例如:原来列表中有两个元素
0 | 历史 |
1 | 环境 |
在前面添加一个元素的时候索引值会变成
0 | 科学 |
1 | 历史 |
2 | 环境 |
所以说是不严谨的
组件上使用v-for
可以在组件上直接使用v-for但是不会将任何数据传到组件里面,因为组件有自己独立的作用域,将数据传递到组件中需要用props
省略.....后面再说
数组变化侦测
侦听数组变化,在他们被调用时触发相关的更新:
push()向数组的末尾添加一个或多个元素,并返回新的长度。
pop()数组最后一位元素删除并返回数组的最后一个元素。
shift()数组的第一个元素从其中删除,并返回第一个元素的值。
unshift()向数组的开头添加一个或更多元素,并返回新的长度。
splice(index,howmany,item1, …, itemX)向/从数组中添加/删除项目,然后返回被删除的项目
第一个参数:表示从哪个索引位置(index)添加/删除元素
第二个参数:要删除的项目数量。如果设置为 0,则不会删除项目。
第三个参数:可选。向数组添加的新项目。
splice(1,2,‘a’,‘b’) 从索引位置(index:1)删除,删除2个元素,并添加2个新元素来替代被删除的元素
splice(1,0,‘a’)从索引位置(index:1)添加,添加两个元素
sort()正序
reverse()倒序
<label for="test">label标签</label>
<input type="text" id="test">
当点击label标签内的文本后,就会触发绑定的表单元素。也就是说,当用户渲染该标签时,浏览器就会自动将焦点转到绑定的表单控件上。
过滤器filter(vue3已淘汰)只能在vue2中使用
可以用在两个地方:1.插值语法2.v-bind
通过管道符进行·调用
<div :id='rawid|过滤器'>
{{message|过滤器}}
</div>
私有过滤器(在Vue不同实例中不能通用只能在当前实例使用)
<div id="app">
<p>{{message|filterL}}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'hellow shuaige',
},
filters: {
// 过滤器函数形参永远都是管道符前面的那个值
filterL(val) {
// 取索引对应的字符串
const vl = val.charAt(0).toUpperCase();
// 截取字符串从指定索引向后截取不包括当前索引
const ou = val.slice(1, 5);
return vl + ou;
},
},
});
</script>
</body>
全局过滤器挂在Vue全局指令上
// 全局过滤器Vue.filter(过滤器名字,回调函数)
Vue.filter('filterL', (val) => {
const vl = val.charAt(0).toUpperCase();
// 截取字符串从指定索引向后截取不包括当前索引
const ou = val.slice(1, 5);
return vl + ou;
});
全局过滤器和私有过滤器冲突,私有过滤器优先级高
也可以通过管道符调用多个过滤器
侦听器Watch
监视数据变化时而调用的函数,在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:
但是学习之前需要了解一下ref声明响应式状态,主要用于组合式API中
为什么要使用ref?
在模板中使用了一个ref,改变ref时,vue会自动检测到变化,并更新相应的dom。通过依赖追踪的响应式系统实现的。当一个组件被首次渲染时,Vue会在追踪渲染的过程中使用的每一个ref,当ref被修改时,会触发追踪它的这个组件重新渲染一次。
<script setup>
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
const loading = ref(false)
// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {//includes是查询字符串中是否包含某个字符
loading.value = true
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
answer.value = (await res.json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
} finally {
loading.value = false
}
}
})
</script>
<template>
<p>
Ask a yes/no question:
<input v-model="question" :disabled="loading" />//默认不能选中是false
</p>
<p>{{ answer }}</p>
</template>
侦听que's'ting,查看输入字符中是否包含问号,包含?时就让输入框不能输入,调用随机返回api
watch
的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:
const x = ref(0)
const y = ref(0)
// 单个 ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter 函数
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
注意,你不能直接侦听响应式对象的属性值
const obj = reactive({ count: 0 })
// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
需要返回这个属性的getter函数值
// 提供一个 getter 函数
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
即时回调的侦听器(immediate:true)
页面打开先执行一次
username: {
handler(n, o) {
console.log(n);
},
immediate: true,
},
一次性侦听器once:true 3.4+
当数据发生变化时只触发一次
watcheffect()
简化请求远程资源的监听,不用多次调用
const todoId = ref(1)
const data = ref(null)
watch(
todoId,
async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
},
{ immediate: true }
)
简写为
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
而且回调会立即执行,不需要指定 immediate: true
。在执行期间,它会自动追踪 todoId.value
作为依赖(和计算属性类似)。每当 todoId.value
变化时,回调会再次执行。有了 watchEffect()
,我们不再需要明确传递 todoId
作为源值。
watch和Watcheffect的区别
1.watch不会追踪回调函数里面访问到的东西。只有数据发生改变后才会触发回调,可以准确的控制回调函数触发时机;(可定制)
2.watcheffect可以追踪到回调函数里面的属性,代码更简洁,但是响印依赖关系不那么明确。(不可定制)
同步侦听器
import { watchSyncEffect } from 'vue'
watchSyncEffect(() => {
/* 在响应式数据变化时同步执行 */
})
计算属性computed
通过一系列运算后得出来的值,动态计算出来的值可以被模板结构或methods方法使用
插slice、splice、split三者区别
slice 截取字符串或数组,并返回一个新的字符串或数组
splice可以对数组进行插入删除替换返回删除的数组元素
split以什么字符分割字符串返回一个数组
<div id="app">
<div>
<input type="text" v-model="message" />
<p>{{messageRe}}</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'hellow',
},
computed: {
messageRe() {
return this.message.split('').reverse().join('');
},
},
});
计算属性所依赖的值发生改变时,计算属性的值也会发生改变
计算属性和侦听属性
计算属性相对于监听属性来说代码更简洁,计算属性默认只有一个getter,但是需要的时候也可以创建一个setter
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
Axios基本使用
axios({
metnod:"请求类型",
url:"请求地址"
}).then((result)=>{
}).catch((err)=>{
})
Vue-cli脚手架
是vue.js的开发标准工具。简化webpack创建工程化项目的过程。
安装
npm i -g @vue/cli
创建项目
vue create 项目名称
通过main.js把App.vue渲染到index.html的指定区域中
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),将组件渲染到页面
}).$mount('#app')提取dom元素主要是query函数也就是queryselector查找第一个符合的dom元素,也就是··。。。。。。。。。。。。el绑定的元素,但是,el不能是body或者html,原因是vue在挂载是会将对应的dom对象替换成新的div,但body和html是不适合替换的。
组件化开发(封装思想,一件多用)
三个组成部分:template、script、style
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld,
},
};
</script>
<style lang="less">启用less
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
组件中的data必须是一个函数,里面要return一个对象
data(){
return{
name:;;;;;;
}
}
组件中定义methods方法
methods: {
add() {
alert('哇哈哈');
},
},
使用组件的步骤:
1.在当前组件中暴露出去,在需要用到该组件的里面导入组件
import from
2.注册组件(调入后在components中注册组件)
export default:{
compoents:{
组件名
}
}
3.在template中以标签形式直接使用该组件
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
通过components注册的是私有组件。
全局组件注册使用
main.js
import a from b
Vue.component('A',a)
props(自定义属性)
在自己组件中声明
props:{
name:String
}
父组件中赋值:
<zujian name='张三'><zujian>
传数字用v-bind:
<All :msg="0"></All> 传的就是数字0,不使用就是字符0
props值只读直接修改会报错,想修改需要在data中声明变量接受,从this挂载的props赋值给
props:{
num
}
data(){
return{
count:this.num
}
}
配置默认值
props:{
num:{
default:0
}
}
明确知道数据类型后可以设置接受数据的类型
props:{
num:Number/
num:{
type:Number
required:true//必填项,默认值不算必须从组件中传过来的值
}
}
样式冲突解决:scoped
.vue中的样式默认加载到全局中会发生样式冲突
给当前组件添加scoped的时候组件实例生成一个唯一标识,给组件中的每个标签对应的dom元素添加一个标签属性,但是不会在编辑页面显示
<template>
<div class="example" data-v-49729759>hello world</div>
</template>
<style scoped>
.example[data-v-49729759] {
color: red;
}
</style>
缺点:父元素添加了scoped的样式想修改子元素中的标签时修改不了(类似信息可以编辑但是没有网),但是没有加scoped的里面又会生效于所有组件
当在style前面添加、/deep/的时候就可以修改子元素的样式相当于后代选择器
加了scoped的样式唯一标识是在后面:
h5[data-v-3vxxxx]{
}
/deep/ h5{
}
就是
[data-v-3vxxxx] h5{
}
是
[data-v-3vxxxx] 就是父元素的唯一标识
使用第三方库的时候需要修改一些样式的时候用到/deep/
万字 基础篇结束 共10999个字