官网链接:
https://cn.vuejs.org/
什么是vue:
渐进式JavaScript 框架
vue-cli链接:
https://cli.vuejs.org/
vue-cli安装:
npm install -g @vue/cli
vue -V
创建一个项目:
vue create xxxxxx
模版语法:
文本插值 {{ }}
<span>Message: {{ msg }}</span>
原始 HTML v-html
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
Attribute 绑定
<div v-bind:id="dynamicId"></div>
简写 <div :id="dynamicId"></div>
同名简写 <div :id></div>
布尔型 Attribute
<button :disabled="isButtonDisabled">Button</button>
当 isButtonDisabled 为真值或一个空字符串 (即 <button disabled="">) 时,
元素会包含这个 disabled attribute。而当其为其他假值时 attribute 将被忽略。
动态绑定多个值
const objectOfAttrs = { id: 'container',class: 'wrapper' }
<div v-bind="objectOfAttrs"></div>
使用 JavaScript 表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
调用函数
<time :title="toTitleDate(date)" :datetime="date">{{ formatDate(date) }}</time>
条件渲染:
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
也可以在 <template> 上使用
<h1 v-show="ok">Hello!</h1>
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要频繁切换,则使用 v-show 较好;
如果在运行时绑定条件很少改变,则 v-if 会更合适
当 v-if 和 v-for 同时存在于一个元素上的时候,v-if 会首先被执行
双向绑定:
v-model
<input v-model="text">
Class 与 Style 绑定:
<div :class="{ active: isActive }"></div>
上面的语法表示 active 是否存在取决于数据属性 isActive 的真假值。
const classObject = reactive({ active: true,'text-danger': false })
<div :class="classObject"></div>
绑定一个数组来渲染多个 CSS class
<div :class="[activeClass, errorClass]"></div>
绑定内联样式
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
const styleObject = reactive({ color: 'red',fontSize: '30px' })
<div :style="styleObject"></div>
路径替代:
@ 代表src根路径
<img :src='@/assets/a.png' />
模板中用到的图片,可以放置在assets目录
在数据中定义的路径,图片放置publuc目录
事件处理:
用法:v-on:click="handler" 或 @click="handler"
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">Submit</button>
<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form ', event)">Submit</button>
function warn(message, event) {
// 这里可以访问原生事件
if (event) { event.preventDefault() }
alert(message)
}
事件修饰符
<!-- 单击事件将停止传递 -->
<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>
页面自适应:
解决方案,引入淘宝的自适应js
- 局部就在页面引入
- 全局就在main引入
组件:
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
template: `<button @click="count++">You clicked me {{ count }} times.</button>`
// 也可以针对一个 DOM 内联模板:
// template: '#my-template-element'
}
样式局部化:
<style scoped ></style>
原理
在节点添加自定义属性 data-v-xxx
根据属性选择器添加样式
插槽:
<slot></slot>
<FancyButton>Click me!</FancyButton> <!-- 插槽内容 -->
<button class="fancy-btn"><slot></slot> </button><!-- 插槽出口 -->
具名插槽 <slot> 元素可以有一个特殊的 attribute name
<div class="container">
<header><slot name="header"></slot></header>
<main><slot></slot></main>
<footer><slot name="footer"></slot></footer>
</div>
<template v-slot:header> 可以简写为 <template #header>
<BaseLayout>
<template v-slot:header></template><!-- header 插槽的内容放这里 -->
</BaseLayout>
插件:
下载插件
引用
全局在main导入
局部在组件导入
配置
样式穿透:
::v-deep 通用
>>>
/deep/
生命周期:
data:
export default {
data(){
age = 11 //静态属性不能双向绑定
return { name: 'xxxx' } //属性双向绑定
},
methods:{ //调用多次,执行多次
newName() { this.name = 'yyyy' }
},
computed:{ //计算属性有缓存,只计算一次
changeName(){ return this.name + 'aa'} //不能修改
changeAge(){//这种写法可以修改
get() { return this.age},
set( val ){ this.age = val }
}
}
}
axios二次封装:
import axios from 'axios';
const service = axios.create({// 创建axios实例
baseURL: process.env.VUE_APP_BASE_API, // api的base_url
timeout: 5000 // 请求超时时间
});
service.interceptors.request.use(// 请求拦截器
config => {
// 可以在这里添加请求头等信息
return config;
},
error => {
// 请求错误处理
console.log(error); // for debug
Promise.reject(error);
}
);
service.interceptors.response.use(// 响应拦截器
response => {
// 对响应数据做处理,例如只返回data部分
return response.data;
},
error => {
// 响应错误处理
console.log('err' + error); // for debug
return Promise.reject(error);
}
);
export default service;
解耦:
import service from '@/utils/request';
// 获取用户列表
export function getUserList(params) {
return service({
url: '/user/list',
method: 'get',
params
});
}
调用:
getUserList({ page: 1, pageSize: 10 }).then(data => {
console.log(data);
});
路由:
<div id="app">
<p>
<!-- 使用 router-link 组件来导航. 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [{ path: '/foo', component: Foo },{ path: '/bar', component: Bar }]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({ router }).$mount('#app')
路由守卫:
全局前置守卫:
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// 如果用户未能验证身份,则 `next` 会被调用两次
next()
})
组件内守卫:
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
路由独享守卫:
const router = new VueRouter({
routes: [{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {// ...}
}]
})
watcher 函数:
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},// 该回调将会在侦听开始之后被立即调用
d: {
handler: 'someMethod',
immediate: true
},
vuex:
持久化数据:
npm install vuex-persistedstat
vue.config.js配置:
https://blog.csdn.net/muzidigbig/article/details/115665717
output.path:硬盘上的路径,也就是你打算把文件打包到你的哪个目录,也就是各个牛人说的绝对路径!与发布时的路径完全无关。
output.publicPath:主要用来转换url中的相对路径的。如果你引用到包含url的资源,一定要配置output.publicPath。配置了此项,webpack在打包时才能根据配置动态修改uri中的相对值。
-------------------------------------------------------------------------------------------------------------------------
NUXTJS 2 框架:
安装: npx create-nuxt-app <项目名>
选择安装项目:
生命周期:
nuxtServerInit,在store文件夹下建立index.js文件。
此生命周期会全局运行,无论访问那个vue文件,都会走
nuxtServerInit 可接收两个参数store,content
export const state = {
token: "123456",
};
export const mutations = {
setToken(state, token) {
state.token = token;
},
};
export const actions = {
/**
*
* @param {*} store 可获取到vuex上下文的数据
* @param {*} content 可获取到nuxt上下文的数据
*/
nuxtServerInit(store, content) {
store.commit("setToken", "abc123");
console.log("nuxtServerInit", store);
},
};
middleware 中间件,第二个生命周期,也是执行每个vue文件都会运行的
需先在nuxt.config.js中进行配置router,设置的是全局middleware中间件
项目根目录下建立middleware文件夹,再建auth.js文件
export default function ({ store, route, redirect, params, query, req, res }) {
// 根据获取到的参数,可以去判断路由跳转到哪个具体页面,或者根据参数去处理下其他逻辑
console.log("middleware auth");
}
也可以设置局部的中间件,如建立一个list.vue,
middleware文件夹下建立一个list.js,调用如下:
list.vue
<template>
<div>list 页面</div>
</template>
<script>
export default {
name: "list",
middleware: "list", // 使用局部的中间件
// 第二种写法如下
middleware(){
console.log('middleware list 局部')
}
};
</script>
list.js
export default function () {
console.log("middleware list 局部");
}
全局的中间件会先执行,然后再执行局部的中间件
validate 校验路由参数的,第三个生命周期执行,一般写在vue文件里
<template>
<div>
首页
<Tutorial />
</div>
</template>
<script>
export default {
name: "IndexPage",
validate({ params, query }) {
// 判断路由传参对不对,若是不符合规范,则可让页面跳转到404页面,不至于页面出现空白情况
console.log("validate");
return true;
},
};
</script>
asyncData 方法会在组件(限于页面组件)每次加载之前被调用。
它可以在服务端或路由更新之前被调用。
在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,
你可以利用 asyncData方法来获取数据并返回给当前组件
// 注意:由于asyncData方法是在组件 初始化 前被调用的,
//所以在方法内是没有办法通过 this 来引用组件的实例对象。
asyncData({ store, params }) {
// 再此可调用接口,请求数据
console.log("asyncData");
},
fetch 方法的第一个参数是页面组件的上下文对象 context,
我们可以用 fetch 方法来获取数据填充应用的状态树。
为了让获取过程可以异步,你需要返回一个 Promise,
Nuxt.js 会等这个 promise 完成后再渲染组件。
// 警告: 您无法在内部使用this获取组件实例,fetch是在组件初始化之前被调用
fetch({ app, store, params }) {
console.log("fetch");
},
服务端与客户端共有的生命周期
接下来是vue中生命周期,比较常用,就不做解释里。
- beforeCreate
- created
客户端的生命周期
- beforeMount() {},
- mounted() {},
- beforeUpdate() {},
- updated() {},
- beforeDestroy() {},
- destroyed() {},
路由:
重构引用原来的router文件
持久化数据:
style:
nuex.config.js配置,全局样式
使用scss步骤
- 安装插件
- 标记 scoped lang
plugins:
定义全局插件或者第三方插件配置,在页面之前调用
element-ui引用配置
axios:
配置代理:
loading:
重构:
npm install vue-verify-plugin -S
项目上线:
-------------------------------------------------------------------------------------------------------------------------
VUE 3
脚手架:
什么是vite,vite是构建工具,vite 开发效率高
vue-cli 2.0 | 3.0, vue create xxx ,是基于webpack构建
vite创建项
npm init @vitejs/app xxx
创建router文件夹,新建index.js文件
解决@根目录导入问题
定义数据:
数据截持原理:
setup语法糖插件:
npm install unplugin-auto-import
torefs:
结构数据转变响应式
watch:
生命周期:
路由:
组件传参:
父传子
子传父
兄弟之间传值:
插槽:
传送:
动态组件:
异步组件:
https://vueuse.nodejs.cn/core/useIntersectionObserver/
组件按需引入,用户访问到了该组件再加载组件
场景一
import { useIntersectionObserver } from '@vueuse/core'
const target = ref(null)
const targetIsVisible = ref(false)
const { stop } = useIntersectionObserver( target, ([{ isIntersecting }], observerElement) => { targetIsVisible.value = isIntersecting }, )
<template> <div ref="target"> <h1>Hello world</h1> </div> </template>
场景二
美 [s??spens]
场景三
混入:
mixin,分发vue组件中的可复用的功能
创建文件夹mixins,新建文件mixin.js
setup写法
选项势写法:
依赖注入:
provider | inject
vuex:
pinia:
安装
npm install pinia
创建文件夹store,新建文件index.js
组件中使用
持久化
设置代理
登录加密:
一、安装 crypto-js npm install crypto-js
二、引入crypto-js 支持ES6导入、Modular
import CryptoJS from "crypto-js"; 或者 const CryptoJS = require("crypto-js");
三、设置密钥和密钥偏移量
// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse("1234123412341234");
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse("1234123412341234");
四、封装加密方法
/* 加密方法 @param data @returns {string} */
export function encrypt(data) {
if (typeof data === "object") {
try {
// eslint-disable-next-line no-param-reassign
data = JSON.stringify(data);
} catch (error) {
console.log("encrypt error:", error);
}
}
const dataHex = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.ciphertext.toString();
}
五、封装解密方法
/* 解密方法 @param data @returns {string} */
export function decrypt(data) {
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
六、使用方法
import { decrypt, encrypt } from "@/utils/encrypt";
const data = "13172"
const encryptText = encrypt(data);
console.log("加密", encryptText);
const decryptText = decrypt(encryptText);
console.log("解密", decryptText);
解决 vite 不能使用 require
文件下载
视频播放
-------------------------------------------------------------------------------------------------------------------------
NUXT3
安装:
npx nuxi@latest init <project-name>
安装失败解决方法:
运行项目:
- cd 到目录执行 npm i
- npm run dev
文件路由:
seo优化:
useSeoMeta({
title:'',
...
})
https://nuxt.com/docs/getting-started/seo-meta
组件库安装:
npm i @vant/nuxt
nuxt.config.js配置
接口:
export default defineEventHandler(async (event) => { // ... Do whatever you want here })
请求数据:
const { data: count} = awaituseFetch('/api/count')
浏览器插件:
vs插件:
预渲染解决方案:
本文暂时没有评论,来添加一个吧(●'◡'●)