Vue是一套用于构建用户界面的渐进式框架
vue的核心库只关心视图层,不仅易于上手,还便于与第三方库或既有项目整合
CDN:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
1.使用Vue打印hello ,Vue!
<body>
<!-- {{}} : 小胡子语法(插值符)-->
<div id="app">{{msg}}</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
//页面打印hello world
//1.使用原生的js
//2.生成vue的app实例
var app = Vue.createApp({
//将模板中的内容编译成标准的html结构,如果没有template选项的话,vue会找到挂载点,
//并将挂载点的innerhtml拷贝过来当模板.
template: `
<div>{{num}}</div>
`,
data: function () {
return {
msg: "Hello Vue",
num: 0
}
}
});
//挂载app
app.mount("#app");
</script>
</body>
如何理解前端渲染? -----将数据填充到html标签中
前端渲染方式:
原生js拼接字符串:
'<li><span>'+num+'</span></li>'
使用前端模板引擎:
<li>${num}</li>
{{}} : 小胡子语法,插值符, data中的状态可以插入到模板中,其中可以写任意的js表达式。
<div>{{1+1}}</div>
<div>{{Date.now()}}</div>
<div>{{arr.join('')}}</div>
<style type="text/css">
[v-cloak]{
/* 元素隐藏 */
display: none;
}
</style>
</head>
<body>
<div id="app">
<!-- 让带有插槽语法的div添加v-cloak属性
在数据渲染完后,v-cloak属性会被自动去除,
v-cloak一旦移除也就没有该属性了
那么属性选择器就选择不到改标签
即对应的标签都将变为可用 -->
<div v-cloak>{{msg}}</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "Hello, Vue!"
}
}
});
app.mount("#app");
</script>
</body>
<body>
<div id="app">
<!-- 注意:在指令中不要写插值语法 直接写对应的变量名称
在 v-text中赋值的时候不要写插值语法,一般属性中不加{{}},
直接写对应的数据名 -->
<p v-text="msg"></p>
<p>
<!-- Vue中只有标签的内容才使用插值语法 -->
{{msg}}
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "Hello Vue",
}
}
});
app.mount("#app");
</script>
</body>
<body>
<div id="app">
<p v-html="html"></p> <!-- 输出:html在渲染的时候被解析 -->
<p>{{msg}}</p> <!-- <span>输出:通过双括号绑定</span> -->
<p v-text="text"></p> <!-- <span>输出:通过v-text绑定</span> -->
<p>
<!-- Vue中只有标签的内容才使用插值语法 -->
{{msg}}
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "<span>Hello, Vue!</span>",
text: "<h2>通过v-text绑定</h2>",
html : "<h1>html在渲染的时候被解析</h1>"
}
}
});
app.mount("#app");
</script>
</body>
<body>
<div id="app">
<span v-pre>{{v-pre是不需要编译就显示的}}</span>
<!--即使是小胡子语法,但是也显示{{msg}}-->
<span v-pre>{{msg}}</span>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "Hello Vue",
}
}
});
app.mount("#app");
</script>
</body>
<body>
<div id="app">
<span v-once>{{msg}}</span>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "Hello Vue",
}
}
});
app.mount("#app");
</script>
</body>
v-model是一个指令,限制在 ,,<textarea>,中使用。或者自定义组件中。
<body>
<div id="app" v-cloak>
<div>{{msg}}</div>
<!-- once只会改变一次 -->
<!-- <div v-once>{{msg}}</div> -->
<!-- 当输入框中的内容改变的时候,页面上的msg会自动更新 -->
<input type="text" v-model="msg">
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
msg: "Hello Vue",
num: 0
}
}
});
app.mount("#app");
</script>
</body>
练习:使用v-model分别对:单选,多选,文本框,下拉框进行双向数据绑定
MVC是后端分层的开发概念,MVVM是前端视图层的概念。主要关注于视图分离,也就是说:MVVM把前端的视图层,分为了三部分:Model,View,ViewModel
<body>
<div id="app" v-cloak>
<!-- 使用v-for遍历数组 -->
<ul >
<li v-for="item in arr">{{item}}</li>
</ul>
<!-- 增加下标 -->
<ul>
<li v-for="(item,index) in arr">{{index}} - {{item}}</li>
</ul>
<!-- 使用v-for遍历对象 -->
<p v-for="val in obj">{{val}}</p>
<!-- 增加键 -->
<p v-for="(val,key) in obj">{{key}} : {{val}}</p>
<!-- 增加下标 -->
<p v-for="(val,key,idx) in obj"> {{idx}} - {{key}} : {{val}}</p>
<!-- 使用v-for遍历字符串(比较少用) -->
<span v-for="c in msg">{{c}}</span><br>
<!-- 使用v-for实现分页效果 -->
<a href="#" v-for="num in 10" style="margin-left: 10px;">{{num}}</a>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
var app = Vue.createApp({
data: function () {
return {
arr:['banana','apple','watermelon'],
obj:{
name:'周飘',
age:18,
gender:'female'
},
msg:"hello vue!"
}
}
});
app.mount("#app");
</script>
</body>
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。v-else
为 v-if
添加一个“else 区块”;v-else
元素必须跟在一个 v-if
或者 v-else-if
元素后面,否则它将不会被识别。v-else-if
提供的是相应于 v-if
的“else if 区块”。它可以连续多次重复使用v-else
类似,一个使用 v-else-if
的元素必须紧跟在一个 v-if
或一个 v-else-if
元素后面。<div id="app">
<div v-if="flag">Hello World!</div>
<div>
<!-- 千万不要无中生有 -->
<div><input type="text" v-model="score" /></div>
<div>
<h1 v-if="score>=90">A</h1>
<h1 v-else-if="score>=80">B</h1>
<h1 v-else-if="score>=70">C</h1>
<h1 v-else>D</h1>
</div>
<ul>
<li v-for="item in stuList">{{item.name}}</li>
</ul>
</div>
</div>
v-show
。其用法基本一样<div v-show="score>80">显示</div>
v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为 display
的 CSS 属性。v-show
不支持在 <template>
元素上使用,也不能和 v-else
搭配使用。v-if与v-show的对比
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建v-if
也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display
属性会被切换。v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if
会更合适。v-if与v-for使用注意事项(面试题)
v-if
和 v-for
同时存在于一个元素上的时候,v-if
会首先被执行。v-if
比 v-for
的优先级更高。这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名。解决方案:在外新包装一层 <template>
再在其上使用 v-for
可以解决这个问题 (这也更加明显易读):
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
<input type='button' v-on:click='num++' />
<input type='button' @click='num++' />
<button v-on:click="say">Hello</button>
<button v-on:click="say()">Say Hi</button>
默认传参:如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数
<button v-on:click="handle2">点击2</button>
手动传参:不带事件对象的传参
<button v-on:click="handle2(123,456)">点击2</button>
手动传参并获取事件对象:
如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event
<button v-on:click="handle2(123,456,$event)">点击2</button>
<body>
<div id="div">
<div>{{num}}</div>
<div>
<!-- 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数 -->
<button v-on:click="handle1">点击1</button>
<!-- 如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,
并且事件对象的名称必须是$event -->
<button v-on:click="handle2(123,456,$event)">点击2</button>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const app = Vue.createApp({
data: function () {
return {
num: 0
}
},
//存放一些方法,methods中的方案,可以在模板中被访问到
methods: {
handle1: function (event) {
console.log(event.target.innerHtml);
},
handle2: function (p, p1, event) {
console.log(p, p1);
console.log(event.target.innerHtml);
//在方法中,要访问状态需要添加this
this.num++
//在一个方法中 访问 其他方法, 也需要添加this
//this.handle2();
}
},
}).mount('#div');
</script>
</body>
.stop
:阻止冒泡.prevent
:阻止默认行为.self
:只有当事件源等同事件绑定元素时,才会执行回调.capture
:捕获.once
:点击事件最多被触发一次
.passive
:移动端使用v-on
或 @
监听按键事件时添加按键修饰符。<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />
Vue 为一些常用的按键提供了别名:
.enter
.tab
.delete
(捕获“Delete”和“Backspace”两个按键).esc
.space
.up
.down
.left
.right
使用v-bind动态绑定属性
<input type='text' placeholder="请输入你的年龄" v-model='age'/>
<a v-bind:herf="age>18?url1:url0" target="_blank"/>
使用v-bind动态绑定样式
<div id="app">
<button @click="flag=!flag">{{flag?'开灯':'关灯'}}</button>
<!-- 动态样式的写法1: 1. 动态style属性 2. style 后面跟对象-->
<div
class="box"
v-bind:style="{backgroundColor: !flag?'red':'black'}"
></div>
<!-- 动态样式的写法2: 1. 动态类名 2. 写成对象的形式, 对象的key就是是否添加的类名 -->
<!-- 3. 对象的值是个boolean值, 如果为true -->
<!-- 4. v-bind绑定的类名 不会对已有类名产生影响 -->
<div class="box" v-bind:class="{red: flag, black: !flag}"></div>
<div
class="box"
v-bind:class="[ flag?'red':'black', {border: flag}]"
></div>
</div>
类似于函数
函数:长串的代码 拆成函数 ,实现更好的代码的可读性,一些重复的代码 也可以封装成函数,实现代码的复用
页面结构非常的多,重复的结构。
组件:1、把大的页面通过组件分割成一块块的,方便维护和代码的阅读(页面组件)
2、出现重复的页面结构,封装成组件 实现复用(通用组件)
1、注册组件
- 全局注册
//方法1:直接使用数组接收
props:[]
//方法2:使用对象,可以定义接收的数据类型,是否必要,以及默认值等
props:{
name:{
type:String,
required: true, //必须要传的prop
},
vote:Number,
total:{
type: Number
default:0
}
}
可以使用v-bind语法糖简化通信方式 inheritAttrs:false 不需要的属性不显示//设为false之后,不在props中的attrs也不要渲染在标签上
如何在自定义组件上使用v-model 1)在自定义组件上使用v-model 就是要求时间的名称 update:[propName] @click = $emit("update:num",num+1) 父组件接收: v-model:num = "num" 2) 使用modelValue接收(唯一的)
emits选项 vue如何判定click是原生的还是子组件传过来的? 答:会执行两次
emits:["click"]//用来声明当前自定义组件中,会触发的事件. 尽量避免歧义
vue开发者工具
组件的另一种通信方式:插槽
子组件:
// slot vue中提供的内置组件
// slot 插槽起到了一个占位的作用
app.component("MyCom", {
template: `
<div class="my-com">
子组件
<div>
<slot></slot>
</div>
</div>
`,
});
子组件内部使用:slot内置组件实现占位作用,接着再父组件中插入一段结构.
父组件:
<my-com>
<h1>hello slot(插槽)!</h1>
</my-com>
插槽也是一种父子组件之间的通信方式 通过插槽 父组件可以把一段(模板的)结构传递给子组件.
具名插槽
子组件
app.component("MyCom", {
template: `
<div class="my-com">
<div class="header">
<slot name="header"></slot>
</div>
<div class="body">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
`,
});
父组件:
<my-com>
<template v-slot:header>
<h1>真正的头部</h1>
</template>
<template #default>
<h2>默认的内容</h2>
</template>
<template #footer>
<h3>底部</h3>
</template>
</my-com>
子组件传状态给父组件
子组件:
app.component("MyCom", {
template: `
<div class="my-com">
<div class="header">
<slot name="header" :msg="msg" :age="age"></slot>
</div>
<div class="body">
<slot :msg="msg" :age="age"></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
`,
data() {
return {
msg: "jack",
age: 10,
};
},
});
父组件:
<my-com>
<template v-slot:header="scopedSlots">
<h1>真正的头部</h1>
{{scopedSlots}}
</template>
<!-- {msg:"jack", age: 10} -->
<!-- 对象的解构写法 -->
<!-- #default="{msg, age}" 声明了2个变量 msg, age-->
<template #default="{msg: text, age}">
<h2>默认的内容</h2>
{{text}} {{age}}
</template>
ES Module 1.每个js文件就是一个模块 2.模块中的变量、方法如果要在其它模块使用的话,必须要主动的导出 ·按需导出具名导出 ·默认导出 3.一个模块要使用其它模块中的变量,先要导入 ·按需导入 ·默认导入
temptate是用字符串的形式在编写模板 1·这些字符串会在项目运行时,在浏览器中被编译为js的函数(性能不太好) 2·在字符串中编写代码,体验很差 为了解决这个问题,Vue为我们提供了一种单文件组件(SFC) 单文件组件的格式是vue(vscode需要安装插件VueLanguageFeatures(volar)) vue文件用来编写单文件组件,vue文件本身并不能被浏览器所识别 所以它必须要被构建工具(vite)打包后,才可使用 同时vue文件在打包时,构建工具会直接将template转换为函数无需再浏览器中在去编译,这样一来性能也会有所提升
SFC 文件以 .vue
扩展名结尾,由三个部分组成: <template>
、<script>
和 <style>
。
<template>
<!-- HTML 模板 -->
</template>
<script>
// JS 逻辑
</script>
<style>
/* 样式表 */
</style>
Vue 3 支持一系列的模板语法指令,包括插值 {{ }}
、指令 v-if
、v-for
等等。另外,Vue 3 还支持 v-bind:
和 @
语法糖来简化代码编写。
Script 部分是组件中的逻辑部分,可以通过 export default {}
导出一个对象。这个对象中包含了组件的各种属性和方法,如 data
、methods
、computed
等等。
Vue 3 引入了 setup()
函数,用于替代 Vue 2 中的 beforeCreate
和 created
钩子函数。setup()
函数需要返回一个对象,这个对象里的属性和方法会被暴露给组件的 template
部分使用。
Vue 3 中的组件通信主要有 Props、自定义事件和 provide / inject 三种方式。其中,provide / inject 是 Vue 3 新增的 API,用于跨级组件之间的数据传递。
Vue 3 的生命周期钩子函数与 Vue 2 相比并没有太大变化,但是新增了两个钩子函数:beforeUnmount
和 unmounted
,用于在组件卸载前和卸载后执行相应的逻辑。
npx create-vue 项目名
注意,创建好之后需要下载相关的依赖包.(npm i)
vue-router基于vue,帮我我们来构建单页面网页应用的路由系统。
路由的概念:
浏览器地址栏url的变化引起页面的变化(引起页面资源的变化)
后端路由:
前端路由:
单页面应用(SPA)
自始至终只有一个html页面。看到到的不同的内容、路由的跳转都是通过该html页面上的js代码来进行控制的
前端路由的两种模式
1、hash模式 有# 利用了hash (锚点)
<a href="#one">跳转</a>
2、history模式 没有# 利用了html5 window.history对象中的API pushState, 生产环境 使用history模式 需要服务器的配合,服务端不能直接返回404页面,而是依然返回index.html首页
可以通过 npm 或 yarn 安装 vue-router:
npm install vue-router@next # 安装最新版的 vue-router(适用于 Vue3)
在 index.js 中创建 router 实例。
import { createRouter, createWebHistory } from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
}
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
在上面的代码中,createRouter
函数返回一个 router
实例。我们可以定义一个 routes
数组来设置各个地址的路由信息。
使用 const router = createRouter({ ... })
创建单例模式的路由器实例,并通过 history: createWebHistory()
指定了使用 H5 的 History
模式进行路由控制。
Vue Router 目前支持三种路由模式:hash
,history
和 abstract
。其中,hash
模式就是使用 URL 的 hash 来模拟一个完整的 URL,不会向服务器发起请求。而 history
模式则利用了 HTML5 的 history.pushState() 性质,在浏览器记录历史记录时被改写,实现了真正的前端 URL
路由。
最后,在 App.vue 或其他入口服务的根元素中使用 标签并且调用
组件来实现路由控制。例如:
<template>
<div id="app">
<nav class="navbar navbar-light">
<ul class="nav navbar-nav">
<li class="nav-item">
<router-link to="/" class="nav-link">Home</router-link>
</li>
<li class="nav-item">
<router-link to="/about" class="nav-link">About</router-link>
</li>
</ul>
</nav>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
};
</script>
这样,在 Vue 组件中使用 router
就可以通过 import {useRouter} from 'vue-router'
引入 useRouter()
函数,使对应的路由数据能被当前组件感知到,并提供相应的方法以进行 URL 跳转处理。
这就是如何使用 Vue 组合式 API 和 vue-router 进行路由控制。Vue Router 在 Vue 中无疑是不可缺少的一部分,它向开发者们提供了极为便利的前端路由控制手段,大大简化了前端单页应用的构建过程。
组件是一个可以通过点击进行路由跳转的组件。它称作路由链接,使用户能够以用户友好的方式在不同的页面之间导航。 如下所示,是一个简单的使用
组件用于显示当前激活路由所对应的组件。我们经常把它放置在包含 APP 内容布局的父级模板中。
Vue Router 也支持嵌套路由。只需按照下面的示例,创建相应的 Vue 组件和路由配置:
const routes = [
{
path: '/',
component: Home,
children: [
{
path: '',
component: Dashboard // -> Renders default child component (e.g. `/`)
},
{
path: 'about',
name: 'About',
component: About
}
]
}
];
在这个示例中,我们通过 children
属性将另一个路由对象嵌套在当前路由中。当前 Vue 组件会作为父级页面(Home.vue),而 children
中定义的路由则是子组件。
通过动态路由数据,你可以构建出诸如 /user/:id
这样的 URL,并在 /user/42
中捕获 42
,以访问该网站上的单一资源。
const routes = [
{ path: '/user/:id', component: User }
];
const router = createRouter({
history: createWebHistory(),
routes
});
// 现在路由器就完成了!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。