Vue-3
(一)过滤器的基本用法
过滤器(Filters)是vue为开发者提供的功能,常用于文本的格式化。过滤器可用于两个地方:插值表达式、v-bind属性绑定
过滤器应该被添加在javascript表达式的尾部,由“管道符”进行调用
- 过滤器的基本使用
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<div id="app">
<p>message的值是: {{message | capitalize}}p>
div>
<script src="js/v2.6.10/vue.js">script>
<script>
const vm = new Vue({
el: '#app',
data: {
message: 'hello vue.js'
},
// 过滤器函数必须被定义到filters节点之下
filters:{
//形参里面的值就是调用时“管道符”|前面的值
capitalize(message){
console.log(message);
const first = message.charAt(0).toUpperCase();
//强调过滤器中一定要一个返回值
return first+message.substr(1,);
}
}
})
script>
body>
html>
- 私有过滤和全局过滤
在filters节点下的过滤器,成为‘私有过滤器’,因为它只能在当前vm实例所控制的el区域内使用,如果希望在多个vue实例之间共享过滤器,可以创建全局过滤器
-
- 全局过滤器
- 如果全局过滤器和私有过滤器冲突,按照就近原则,优先调用自己的过滤器、
- 全局过滤器必须写在自己的作用域的vm实例之前
- 全局过滤器
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<div id="app">
<p>message的值是: {{message | capitalize}}p>
div>
<div id="name">
<p>name的值是: {{name | capitalize}}p>
div>
<script src="js/v2.6.10/vue.js">script>
<script>
//全局过滤器-独立于每个vm实例之外的
//Vue.filter()方法接收两个参数
//第一个参数,是全局过滤器的名字
//第二个参数,是全局过滤器的“处理函数”
Vue.filter('capitalize',(str)=>{
const first = str.charAt(0).toUpperCase();
return first+str.slice(1);
})
const vm = new Vue({
el: '#app',
data: {
message: 'hello vue.js'
}
})
const vm1 = new Vue({
el: '#name',
data: {
name: 'baekhyun'
}
})
script>
body>
html>
-
- 拓展:上个案例处理时间,可以使用day.js库
-
- 连续调用多个过滤器:过滤器可以串联的进行调用,前一个过滤器的返回值作为后一个过滤器的参数
- 过滤器可以接受参数
- 第一个参数永远是管道符前面待处理的值
- 第二个参数开始,才是调用过滤器时传递过来的参数
- 过滤器的兼容性:过滤器仅在vue 2.x和1.x中受支持,在vue 3.x的版本中删除类过滤器的相关功能
(二)侦听器
watch侦听器运行开发者监视数据的变化,从而针对数据的变化做特定的操作
- 侦听器基本的语法格式
<div class="app"> <input type="text" v-model="username" /> div> <script src="js/v2.6.10/vue.js">script> <script> const vm = new Vue({ el: '.app', data: {username: 'baekhyun'}, //所有的侦听器都应该被定义到watch节点下 watch: { //侦听器本质上是一个函数,要侦听哪一个数据的变化,就把数据名作为方法名,新值在前,旧值在后 username(newVal,oldVal){ //newVal是变化之后的新值 //oldVal是变化之后的旧值 console.log(newVal,oldVal); } } }) script>
- 判断用户名是否被占用
- html
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<div class="app">
<input type="text" v-model="username" />
<div class="notice">div>
div>
<script src="js/v2.6.10/vue.js">script>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
const vm = new Vue({
el: '.app',
data: {username: ''},
//所有的侦听器都应该被定义到watch节点下
watch: {
//侦听器本质上是一个函数,要侦听哪一个数据的变化,就把数据名作为方法名
username(newVal,oldVal){
//newVal是变化之后的新值
//oldVal是变化之后的旧值
//1.调用axios中的ajax请求,判断newVal是否被占用
axios.defaults.baseURL = "http://127.0.0.1:8000";
axios.get("/info",{
params:{
name: newVal
}
}).then(value=>{
const notice = document.querySelector(".notice");
notice.innerHTML = value.data.message;
if(value.data.flag){
notice.style.color = 'green';
}else{
notice.style.color = 'red';
}
})
}
}
})
script>
body>
html>
-
- js
//1.引入express const express = require("express"); //2.创建应用对象 const app = express(); app.all('/info',(request,response)=>{ response.setHeader("Access-Control-Allow-Origin","*"); response.setHeader("Access-Control-Allow-Headers","*"); const names = ['tom','jerry','alice','bob']; const name = request.query.name; if(names.includes(name)){ const obj = { flag: false, message: 'Sorry, the name is already in use' } response.send(JSON.stringify(obj)); }else{ const obj = { flag: true, message: 'Lucky, the name is not in use' } response.send(JSON.stringify(obj)); } }) app.listen(8000,()=>{ console.log("正在监听8000端口"); })
- 侦听器的格式
- 方法格式的侦听器
- 缺点:无法在刚进入页面的时候,自动触发
- 缺点:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器
- 对象格式的侦听器
- 好处:可以通过immediate选项,让侦听器自动触发
- 好处:可以通过deep选项,让侦听器深度监听对象中每个属性的变化
- 方法格式的侦听器
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<div class="app">
<input type="text" v-model.lazy="info.username" />
<div class="notice">div>
div>
<script src="js/v2.6.10/vue.js">script>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
const vm = new Vue({
el: '.app',
data: {
info: {
username: 'baekhyun'
}
},
watch: {
//定义对象格式的侦听器
info: {
//侦听器的处理函数,如果侦听的是对象的子属性的变化,则要但单引号:'info.username',与deep二选一
handler(newVal){
axios.defaults.baseURL = "http://127.0.0.1:8000";
axios.get("/info",{
params:{
name: newVal.username
}
}).then(value=>{
const notice = document.querySelector(".notice");
notice.innerHTML = value.data.message;
if(value.data.flag){
notice.style.color = 'green';
}else{
notice.style.color = 'red';
}
})
},
//immediate选项的默认值是false
//它的作用是控制侦听器是否自动触发
immediate: true,
//开启深度监听,只要对象中有任何一个属性变化了,就会触发“对象的侦听器”
deep: true
}
}
})
script>
body>
html>
(三)计算属性
计算属性指的是通过一系列的运算之后,最终得到的一个属性值
这个动态计算出来的属性值可以被模板结构或methods方法使用
- 特点
- 定义的时候,要被定义为方法
- 在使用计算属性的时候,当普通的属性使用即可
- 好处
- 实现了代码复用
- 只要计算属性中依赖的数据源变化了,则计算属性会重新求值
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
<style type="text/css">
.pic {
width: 200px;
height: 200px;
margin-left: 10px;
}
input {
margin-left: 10px;
}
style>
head>
<body>
<div class="app">
R:<input type="number" class="R" v-model="R"/><br>
G:<input type="number" class="G" v-model="G"/><br>
B:<input type="number" class="B" v-model="B"/>
<hr >
<div class="pic" :style="{backgroundColor: rgb}">{{rgb}}div>
<input type="button" value="按钮" @click="show"/>
div>
<script src="js/v2.6.10/vue.js">script>
<script>
const vm = new Vue({
el: '.app',
data: {
R: 0,
G: 0,
B: 0
},
methods:{
show(){
console.log(this.rgb)
}
},
//所有的计算属性,都要定义到computed节点之下
//计算属性在定义的时候要定义为方法格式
computed:{
//rgb作为一个计算属性,被定义为了方法格式
//最终,在这个方法中,要返回一个生成好的rgb(r,g,b)字符串
rgb(){
return `rgb(${this.R},${this.G},${this.B})`;
}
}
})
script>
body>
html>
(四)axios
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>title>
head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
//如果调用某个方法的返回值是Promise实例,则前面可以添加await
//await只能用在被async修饰的方法中,以此可以方便的使用解构
//解构赋值的时候使用:进行重命名
// 1.使用axios之后,使用async和await进行简化
// 2.使用解构赋值,从axios封装的大对象中,把data属性提取出来
// 3.把解构出来的data属性,使用:进行重命名,一般重命名为{data:res}
const res = axios({
//请求方式
// method: 'GET',
method: 'POST',
//请求路径
url: 'http://127.0.0.1:8000/hello',
//查询URL中的查询参数
params:{},
//请求体参数
data: {}
})
console.log(res);
console.log(res.then(data=>console.log(data)));
script>
body>
html>
(五)vue-cli
- 单页面应用程序SPA(Single page Application)
指的是一个web网站中只有唯一的一个HTML页面,所有的功能与交互都在这唯一的一个页面内完成
- vue-cli:介绍 | Vue CLI (vuejs.org)
vue-cli是vue.js开发的标准工具。它简化了程序员基于webpack创建工程化的Vue项目的过程,是npm上的一个全局包
-
- 安装和使用
- npm install -g @vue/cli:通过 vue -V进行检测看是否有vue-cli的版本号
- 基于vue-cli快速生成工程化的Vue项目:vue create 项目名称
- vue项目中src的目录构成
- assets文件夹:存放项目中用到的静态资源文件,例如css样式表、图片资源
- components文件夹:程序员封装的一些可复用的组件,都要放到components目录下
- main.js:是项目入口文件,整个项目的运行,要先执行main.js
- App.vue:是项目的根组件
- vue项目的执行流程
在工程化的项目中,vue要做的事情很单纯:通过main.js把App.vue渲染到index.html的指定区域中
-
- mian.js解析
//导入Vue这个包,得到Vue构造函数 import Vue from 'vue' //导入App.vue根组件,将来要把App.vue渲染到html页面中 import App from './App.vue' Vue.config.productionTip = false //创建Vue实例对象 new Vue({ //el: '#app', //把render函数指定的组件渲染到html页面中 render: h => h(App), }).$mount('#app') //Vue实例的$mount方法,作用和el属性完全一样
(六)vue组件化开发
组件化的开发指的是:根据封装的思想,把页面上可重用的UI结构封装为组件,从而方便项目的开发和维护
vue是一个支持组件化开发的前端框架
vue中规定:组件的后缀名是.vue,之前接触到的App.vue本质上就是一个vue的组件
- vue组件的三个组成部分
- template->组件的模板结构
- script->组件的javaScript行为
- style->组建的样式
<template> <div class="box"> <h4>{{username}}h4> <h3>{{sex}}h3> <button @click="changeName">点我一下button> div> template> <script> //默认导出,这是固定写法 export default{ //data数据源 //注意:组件里面的data不能指向对象,应该是一个函数 data(){ //这个return出去的{}中,可以定义数据 return { username: 'BAEKHYUN', sex: 'man' } }, methods:{ changeName(){ //在组件中,this表示当前组件的实例对象实例 this.username = 'BBH'; } }, //当前组件中的侦听器 watch:{}, //当前组件中的计算属性 computed:{}, //当前组件中的过滤器 filters:{} } script> <style> /* 在style中如果不添加lang='less'默认是css语法 */ h4 { color: pink; } style>
- 组件之间的父子关系
组件在被封装好之后,彼此之间是相互独立的,不存在父子关系
在使用组件的时候,根据彼此的嵌套关系,形成父子关系
-
- 使用@符号代表src根目录
//webpack.config.js module.exports = { resovle: { alias:{ @: path.join(__dirname,"./src"); } } }
-
- 使用组件的三个步骤
- 使用import语法导入需要的组件
- 使用components节点注册组件
- 以标签形式使用刚才注册的组件
- 使用组件的三个步骤
<template> <div class="box"> 这是一个App根组件 <Left>Left> <Right>Right> div> template> <script> //1.导入要使用的Left和Right组件 import Left from '@/components/Left.vue' import Right from '@/components/Right.vue' //默认导出,这是固定写法 export default{//2.组件注册 components: { 'Left': Left, 'Right': Right } } script> <style> /* 在style中如果不添加lang='less'默认是css语法 */ .box { height: 200px; background-color: orange; } style>
- HTML配置@路径提示插件
https://ext.dcloud.net.cn/plugin?id=4734
- 使用Vue.component全局注册组件
- 使用components注册的是私有组件
- 注册全局组件
在vue项目main.js入口文件中,通过Vue.component()方法,可以注册全局组件
//导入Vue这个包,得到Vue构造函数 import Vue from 'vue' //导入App.vue根组件,将来要把App.vue渲染到html页面中 import App from './App.vue' //1.导入需要被注册的组件 import Count from '@/components/Count.vue' //参数1:字符串格式,表示组件的"注册名称" //参数2:需要被全局注册的那个组件 Vue.component('Count',Count); Vue.config.productionTip = false //创建Vue实例对象 new Vue({ //el: '#app', //把render函数指定的组件渲染到html页面中 render: h => h(App), }).$mount('#app') //Vue实例的$mount方法,作用和el属性完全一样
- 组件里的props
props是组件的自定义属性,在封装通用组件的时候,合理的使用props,可以极大地提高组件的复用性
<template> <div> <h5>Count组件h5> <p>count的值是:{{count}}p> <button @click="count++">+1button> div> template> <script> export default { //props是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值 //自定义属性的名字是封装自定义的 //props中的数据,可以直接在模板结构中被使用 props:['init'], data(){ return { count: this.init } } } script> <style lang="less"> style>
-
- props的default默认值
//在声明自定义属性时,可以通过default来定义属性的默认值
//自定义属性A: {/*配置选项*/}
props: {
init: {
//如果外界使用Count组件的时候,没有传递init属性,则默认值生效
default: 0
}
},
-
- props的type属性
props: {
init: {
//用default属性定义属性的默认值
default: 0,
//使用type属性定义属性的值的类型
//如果传递过来的值不符合此类型,则会在终端报错
type: Number
}
},
-
- props的required必填项
props: {
init: {
default: 0,
type: Number,
//为必填项,必填项校验,检验视为有传值,和默认值没有关系
required: true
}
},
- 组件之间的样式冲突
默认情况下,写在vue组件中的样式会全局生效,因此很容易造成多个组件之间样式冲突的问题
主要原因:
- 单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的
- 每个组件中的样式,都会影响整个index.html页面中的DOM元素
解决方案:1.给每个vue子组件style样式中添加scoped,其本质就是给每个标签添加一个独一无二的属性
2.当使用第三方组件库的时候,如果修改第三方组件默认样式,则需要用到/deep/
-
-
-
-
- 由于给vue子组件的样式中添加了scoped,需要修改第三方组件的默认样式时,如果直接在该子组件中修改,选择器选中的是带有scoped添加的属性的标签,但第三方组件的标签不包含该属性所以筛选不到。因此,我们需要在样式选择器前面添加/deep/,这样在筛选时会变成在拥有scoped添加的属性下查询该制定个标签,这样就可以查询到了。
-
-
-