Vue开发前准备
需要去官网Home | Vue CLI (vuejs.org)安装cli,cli是官方的vue开发环境。
安装成功后,可以通过命令来检测是否安装成功
vue --version
创建项目命令(名字要求全小写)
vue create my-project
选择方式(初学):
然后跳出选择版本的按钮,选择3.x版本即可。
然后就可以进行选择配置文件放在哪里,默认选择第一个即可。
运行操作
npm run serve
项目打包:需要前往需要打包的文件夹下面的终端
命令
切换目录
cd 目录地址
npm run build
解决打包后的vue项目白屏
在vue.config.js
文件中添加以下代码即可
// vue.config.js
module.exports = {
publicPath: './',
}
模板语法
数据绑定语法
通过{}绑定数据,其中data()是一个方法,返回对应的数据值
<template>
<div class="hello">
<h1>HelloWorld</h1>
<h3>{{ message }}</h3>
</div>
</template>
`<script>
export default {
name: 'HelloWorld',
data() {
return {
message: "测试"
}
}
}
</script>`
原始HTML
双大括号会将数据解释为普通文本,而非HTML代码,为了输出真正的HTML,你需要使用指令v-html指令
<p>
Using mustaches:{{rawHtml}}
</p>
<p>
Using v-html directive:<span v-html="rawHtml"></span>
</p>
data(){
return{
rawHtml:"<a href='https://www.fish9.cn'>吃猫的鱼</a>"
}
}
完整示例代码:
<template>
<div class="hello">
<h1>HelloWorld</h1>
<h3>{{ message }}</h3>
<div>{{ rawHtml }}</div> //输出文本
<div v-html="rawHtml"></div> //输出html代码
</div>
</template>
`<script>
export default {
name: 'HelloWorld',
data() {
return {
message: "测试",
rawHtml: "<a href='https://www.fish9.cn'>吃猫的鱼</a>"
}
}
}
</script>`
运行截图:
属性Attribute
Mustache语法不能再HTML属性中使用,然而可以使用v-bind指令
当我们标签中的属性需要发生变化的时候,可以通过v-bing对其进行动态修改。
v-bind 可以简写成 :
<div v-bind:id="dynamicId"></div> 完整写
<div :id="dynamicId"></div> 简写
`<script>
export default {
name: 'HelloWorld',
data() {
return {
dynamicId: 1001
}
}
}
</script>`
使用JavaScript表达式
Vue.js提供完全的js表达式,{{ }}里面可以进行js的相关符号式的操作。
表达式会再当前活动实例的数据作用域下作为JavaScript被解析。有个限制就是,每个绑定都只能包含单个表达式。
条件渲染
指令用于条件性地渲染一块内容,这块内容只能在指令的表达式返回true才会被渲染
<p v-if="flag">我是吃猫的鱼</p>
<script>
export default {
data() {
return {
flag: true
}
}
}
</script>
v-else:
<!-- 条件渲染 -->
<p v-if="flag">我是吃猫的鱼1</p>
<p v-else="flag">我是吃猫的鱼2</p>
<script>
export default {
name: 'HelloWorld',
data() {
return {
flag: false
}
}
}
</script>
上面代码显示的是我是吃猫的鱼2
另一个用于条件性展示元素的是v-show指令,使用方式
<h1 v-show="flag">Hello!</h1>
v-if和v-show的区别
v-if是"真正"的条件渲染,因为它会确保在切换过程中,条件块内的时间监听器和子组件适当地被销毁和重建。
v-if 也是惰性的,如果在初始渲染时条件为假,则什么也不做知道条件第一次变为真时,才会开始渲染条件快。
相比之下,v-show就简单得多-不管初始条件是什么,元素总是会被渲染,并且只是简单地基于css进行切换。
一般来说,v-if 有更高的切换开销,而v-show有更高的初始渲染开销,因此,如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好。
列表渲染
用v-for把一个数组映射位一组元素。
我们可以用v-for指令基于一个数组来渲染一个列表。v-for指令需要使用item in items 形式的特殊语法,其中items是源数据数组,而item则是被迭代的数组元素的别名。
<ul>
<li v-for="item in items">{{ item.message }}</li>
</ul>
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
维护状态
当Vue正在更新使用v-for渲染的元素列表时,它默认使用"就地更新"的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给Vue一个提示,以便它能跟踪每个结点的身份,从而重用和冲i性能排序现有元素,你需要为每项提供一个唯一的key
attribute:
<div v-for="(item,index) in items" :key="item.id|index">
<!--内容-->
</div>
事件处理
可以使用v-on
指令(通常缩写为@符号)来监听DOM事件,并在触发事件时执行一些JavaScript,用法为v-on:click="mathodName"
或使用快捷方式@click="methodName"
<button @click="counter+=1">
Add 1
</button>
data(){
return{
counter:0
}
}
事件处理方法
很多事件处理逻辑会更加复杂,所以直接把JavaScript代码写在v-on
指令中是不可行的,因此v-on
还可以接受一个需要调用的方法名称
<button @click="greet">
Greet
</button>
methods:{
greet(event){
//'event'是原生DOM event
if(event){
alert(event.target.tagName)
}
}
}
实例:
<!-- 事件处理 -->
<button @click="counter += 1">点击{{ counter }}</button>
<button @click="clickHandle">控制台输出"哈哈哈"</button>
<p @click="change">{{ message }}</p><!--点击撤回-->
data() {
return {
message: "测试",
counter: 1
}
},
methods: {
clickHandle() {
console.log("哈哈哈");
},
change() {
//事件中,读取data中的属性,需要通过this.属性
this.message = "消息消失了";
}
}
内联处理器中的方法
相当于"事件传递参数"
<button @click="say('hi')">Say hi</button>
<button @click="say('what')">Say what</button>
methods:{
say(message){
alert(message)
}
}
表单输入绑定
可以使用v-model
指令在表单input
、textarea
及<select>
元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model
本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
<input v-model="message" placeholdere="edit me"/>
<p>
Message is :{{message}}
</p>
data(){
return {
message:""
}
}
修饰符
.lazy
在默认情况下,v-model
在每次input
事件触发后将输入框的值与数据进行同步。你可以通过lazy
修饰符,从而转为在change
事件之后进行同步
<input v-model.lazy="message"/>
<p>
Message is:{{message}}
</p>
data(){
return {
message:""
}
}
trim
如果要自动过滤用户输入的首尾空白字符,可以给v-model
添加trim
修饰符
<input v-model.trim="message"/>
data(){
return {
message:""
}
}
组件基础
单文件组件
Vue单文件组件(又名 *.vue
文件,缩写为SFC)是一种特殊的文件格式,它允许将Vue组件的模板、逻辑与样式封装在单个文件中。
加载组件
第一步 :引入组件 import MyComponentVue from'./components/MyComponent.vue'
第二步:挂载组件compnents:{MyCDomponentVue}
第三步:显示组件<my-componentVue/>
示例代码
MyComponents中代码
<template>
<h3>我是单文件组件</h3>
</template>
`<script>
export default {
name: "MyComponent"
}
</script>
<!-- scoped:如果在style中添加此属性,就代表着,当前样式,只在当前组件中生效-->
<style scoped>
h3 {
color: red;
}
</style>`
App.vue中代码
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
<MyComponents />
<my-components />
</template>
\<script\>
import MyComponents from './components/MyComponents.vue';
import HelloWorld from './components/HelloWorld.vue'
`export default {
name: 'App',
components: {
HelloWorld,
MyComponents
}
}
</script>`
在App.vue中
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织
props组件交互
组件与组件之间进行交互。
App.vue可以向组件传递参数,例如
<MyComponents :title="title" :age="age" :name="name"/>
然后在组件中需要接受传过来的参数,接过来需要给参数赋值类型和默认值。
<script>
export default {
name: "MyComponents",
props: {
title: {
type: String,
default: ""
},
age: {
type: Number,
default: 0
},
name: {
type: String,
//数组和对象必须使用函数返回
default: function () {
return []
}
}
}
}
</script>
完整示例代码:
App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png">
<MyComponents :title="title" :age="age" :name="name"/>
</template>
\<script\>
import MyComponents from './components/MyComponents.vue';
export default {
name: 'App',
data() {
return {
title: "我是一个标题",
age: 20,
name:\["aa","bb","cc","dd"\]
}
},
components: {
MyComponents
}
}
\</script\>
`<style>
#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>
`
MyComponents.vue
<template>
<h3>我是单文件组件</h3>
<h2>{{ title }}</h2>
<p>{{ age }}</p>
<ul>
<li v-for="item, index in name" :key="index">{{ item }}</li>
</ul>
</template>
`<script>
export default {
name: "MyComponents",
props: {
title: {
type: String,
default: ""
},
age: {
type: Number,
default: 0
},
name: {
type: String,
//数组和对象必须使用函数返回
default: function () {
return []
}
}
}
}
</script>
<!-- scoped:如果在style中添加此属性,就代表着,当前样式,只在当前组件中生效-->
<style scoped>
h3 {
color: red;
}
</style>`
自定义事件组件交互
自定义事件可以在组件中反向传递数据,prop
可以将数据从父组件传递到子组件,想要反向操作,可以使用自定义事件实现。
可以通过在组件中自定义方法,向app.vue中传递.
在自定义方法中使用
this.$emit("onEvent", this.message)
然后再app,vue中接收这个方法
<MyComponents @onEvent="getDataHandle" />
methods: {
getDataHandle(data) {
this.message = data
}
}
完整示例代码
MyComponents.vue
<template>
<h3>自定义事件传递数据</h3>
<button @click="sendClickHandle">点我传递</button>
</template>
`<script>
export default {
name: "MyComponents",
data() {
return {
message: "我是MyComponents数据"
}
},
methods: {
sendClickHandle() {
//参数一是字符串,理论上是随意的,但是需要具有意义
//参数二是传递的数据
this.$emit("onEvent", this.message)
}
}
}
</script>
<!-- scoped:如果在style中添加此属性,就代表着,当前样式,只在当前组件中生效-->
<style scoped>
h3 {
color: red;
}
</style>`
App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png">
<MyComponents @onEvent="getDataHandle" />
\<h1\>{{ message }}\</h1\>
\</template\>
\<script\>
import MyComponents from './components/MyComponents.vue';
export default {
name: 'App',
data() {
return {
message: ""
}
},
components: {
MyComponents
},
methods: {
getDataHandle(data) {
this.message = data
}
}
}
\</script\>
`<style>
#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>`
组件生命周期
分类
创建时:beforeCreate
、created
渲染时:beforeMount
、mounted
(网络请求一般放到这里)
更新时: beforeUpdate
、updated
卸载时:beforeUnmount
、unmounted
vue引入第三方扩展
swiper中vue引入官方文档 https://swiperjs.com/vue/
安装指定版本:npm instal --save swiper@8.1.6
Axios发起网络请求
Axios 是一个基于promise的网络请求库
安装
Axios的应用是需要单独安装的npm install --save axios
引入
组件中引入:import axios from "axios"
全局引用:
import axios from "axios"
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount("#app")
`//在组件中调用
this.$axios`
网络请求基本示例
get请求(post请求同理)
axios({
method: "get",
url: "http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php",
data:{
userid:"123",
psw:"123456"
}
}).then(res => {
this.chengpin = res.data.chengpinDetails[0]
})
建议放在组件渲染完成后。
完整示例代码
<template>
<div class="hello">
<p>{{ chengpin.title }}</p>
</div>
</template>
\<script\>
import axios from "axios"
`export default {
name: 'HelloWorld',
data() {
return {
chengpin: {}
}
},
mounted() { //组件渲染完成
axios({
method: "get",
url: "http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php"
}).then(res => {
this.chengpin = res.data.chengpinDetails[0]
})
}
}
</script>`
注意
post请求参数是需要额外处理的
安装依赖 npm install --save querystring
转换参数格式:qs.stringify({})
简单使用
axios.get("url")
.then(res =>{
console.log(res.data);
})
`axios.post("url",stringify({
user:"",
psw:""
})).then(res =>{
console.log(res.data);
})`
Axios网络请求封装
在目录utils下新建request.js用来封装Axios网络请求
import axios from "axios";
import { resolve4 } from "dns";
import querystring from "querystring"
const errqrHandle = (status, info) =\> {
switch (status) {
case 400:
console.log("语义有误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器拒绝访问");
break;
case 404:
console.log("地址错误");
break;
case 500:
console.log("服务器遇到意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
const instance = axios.create({
//网络请求的公共配置
timeout:5000
})
//拦截器最常用的
//发送数据之前
instance.interceptors.request.use(
config =\> {
if (config.method === "post") {
config.data = querystring.stringify(config.data)
}
//config:包含着网络请求的所有信息
return config;
},
error =\> {
return Promise.reject(error)
}
)
`//获取数据之前
instance.interceptors.response.use(
response => {
return response.status === 200 ? Promise.resolve(response) : Promise.reject(response)
},
error => {
const { response } = error;
//错误处理才是我们需要最关注的
errorHandle(response.status,response.info)
}
)
export default instance;`
封装可以新建一个目录api,然后将所有api请求都放在这个文件夹。
path.js //存放路径
const base = {
baseUrl:"主要域名,如:https://www.fish9.cn",
chengpin:"/api/chengpin"
}
`export default base;`
index.js 存放请求的方法
import axios from "../utils/request"
import path from "./path"
const api ={
//成品详情地址
getChengpin(){
return axios.get(path.baseUrl + path.chengpin)
}
}
`export default api`
组件中使用
<script>
import api from "../api/index"
export default{
name:'HelloWorld',
mounted(){
api.getChengpin().then(res =>{
console.log(res.data);
})
}
}
`</script>`
页面关系管理
在vue中,我们可以通过vue-router
路由管理页面之间的关系
Vue Router 是Vue.js的官方路由,它与Vue.js深度集成,让用Vue.js构建单页应用变得轻而易举。
在Vue中引入路由
第一步:安装路由 npm install --save vue-router
第二步:配置独立的路由文件
新建router目录,新建index.js
import { createRouter, createWebHashHistory } from "vue-router"
import HomeView from "../views/HomeView"
//配置信息中需要页面的相关配置
const routes = [
{
path: "/",
name:"home",
component: HomeView
},
{
path: "/about",
name:"about",
//这是异步加载方式
component: () => import("../views/AboutView.vue")
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router;
新建views文件夹两个文件HomeView.vue ,AboutView.vue
AboutView.vue
<template>
<h3>关于页面</h3>
</template>
HomeView.vue
<template>
<h3>首页</h3>
</template>
然后在main.js引入import router from "./router"
,然后再改成:
createApp(App).use(router).mount('#app')
App.vue
<template>
<!-- 路由的显示入口 -->
<router-view></router-view>
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
</template>
\<script\>
export default {
name: 'App'
}
\</script\>
`<style>
#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>`
路由传递参数
第一步:在路由配置中指定参数的key
{
path: "/newsdetails/:name",
name: "newsdetails",
component: () => import("../views/NewsDetailView.vue")
}
第二步:在跳转过程中携带参数
<template>
<ul>
<li><router-link to="/newsdetails/百度">百度新闻</router-link></li>
<li><router-link to="/newsdetails/网易">网易新闻</router-link></li>
<li><router-link to="/newsdetails/头条">头条新闻</router-link></li>
</ul>
</template>
第三步:在详情页面读取路由携带的参数
<template>
<h3>{{ $route.params.name }}新闻详情</h3>
</template>