文章目录
- Vue
- 一、Mixin混入的基础语法
- 二、开发自定义指令
- 三、Teleport传送门功能
- 四、render函数
- 五、插件的定义和使用
- 六、数据校验插件
- 七、Setup函数使用
- 八、ref、reactive响应式引用的用法和原理、toRef以及context参数
- 九、使用Composition API开发Todolist
- 十、computed方法生成计算属性
- 十一、watch 和 watchEffect 的使用和差异性
- 十二、生命周期函数的新写法
- 十三、Provide,Inject,模版 Ref 的用法
- 十四、VueCLI 的使用和单文件组件
- 十五、使用单文件组件编写 TodoList
- 十六、Vue-Router 路由的理解和使用
- 十七、VueX的语法
- 十八、CompositionAPI 中使用 VueX
- 十九、使用axios发送ajax请求
Vue
一、Mixin混入的基础语法
<script>
// mixin 混入
// 组件 data, methods 优先级高于 mixin data, methods 优先级
// 生命周期函数,先执行 mixin 里面的,再执行组件里面的
// 自定义的属性,组件种的属性优先级高于 mixin 属性的优先级
const myMixin = {
number: 1
}
const app = Vue.createApp({
mixins: [myMixin],
number: 2,
template: `
<div>
<div>{{this.$options.number}}</div>
</div>
`
});
app.config.optionMergeStrategies.number = (mixinVal, appValue) => {
return mixinVal || appValue;
}
const vm = app.mount('#root');
</script>
二、开发自定义指令
<script>
// 自定义指令 directive
const app = Vue.createApp({
data() {
return {
distance: 110
}
},
template: `
<div>
<div v-pos:right="distance" class="header">
<input />
</div>
</div>
`
});
app.directive('pos', (el, binding) => {
el.style[binding.arg] = (binding.value + 'px');
})
const vm = app.mount('#root');
</script>
三、Teleport传送门功能
<style>
.area {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 300px;
background: green;
}
.mask {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: #000;
opacity: 0.5;
color: #fff;
font-size: 100px;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
<div id="hello"></div>
</body>
<script>
// teleport 传送门
const app = Vue.createApp({
data() {
return {
show: false,
message: 'hello'
}
},
methods: {
handleBtnClick() {
this.show = !this.show;
}
},
template: `
<div class="area">
<button @click="handleBtnClick">按钮</button>
<teleport to="#hello">
<div class="mask" v-show="show">{{message}}</div>
</teleport>
</div>
`
});
const vm = app.mount('#root');
</script>
四、render函数
<script>
// render function
// template -> render -> h -> 虚拟DOM(JS对象)-> 真实 DOM -> 展示到页面上
const app = Vue.createApp({
template: `
<my-title :level="2">
hello dell
</my-title>
`
});
app.component('my-title', {
props: ['level'],
render() {
const { h } = Vue;
return h('h' + this.level, {}, [
this.$slots.default(),
h('h4', {}, 'dell')
])
}
})
const vm = app.mount('#root');
</script>
五、插件的定义和使用
<script>
// plugin 插件, 也是把通用性的功能封装起来
const myPlugin = {
install(app, options) {
app.provide('name', 'Dell Lee');
app.directive('focus', {
mounted(el) {
el.focus();
}
})
app.mixin({
mounted(){
console.log('mixin')
}
})
app.config.globalProperties.$sayHello = 'hello world';
}
}
const app = Vue.createApp({
template: `
<my-title />
`
});
app.component('my-title', {
inject: ['name'],
mounted() {
console.log(this.$sayHello);
},
template: `<div>{{name}}<input v-focus /></div>`
})
app.use(myPlugin, { name: 'dell'});
const vm = app.mount('#root');
</script>
六、数据校验插件
<script>
// 对数据做校验的插件
const app = Vue.createApp({
data() {
return { name: 'dell', age: 23}
},
rules: {
age: {
validate: age => age > 25,
message: 'too young, to simple'
},
name: {
validate: name => name.length >= 4,
message: 'name too short'
}
},
template: `
<div>name:{{name}}, age:{{age}}</div>
`
});
const validatorPlugin = (app, options) => {
app.mixin({
created() {
for(let key in this.$options.rules) {
const item = this.$options.rules[key];
this.$watch(key, (value) => {
const result = item.validate(value);
if(!result) console.log(item.message);
})
}
}
})
}
app.use(validatorPlugin);
const vm = app.mount('#root');
</script>
七、Setup函数使用
<script>
// 对数据做校验的插件
const app = Vue.createApp({
template: `
<div @click="handleClick">{{name}}</div>
`,
methods: {
test() {
console.log(this.$options.setup());
}
},
mounted() {
this.test();
},
// created 实例被完全初始化之前
setup(props, context) {
return {
name: 'dell',
handleClick: () => {
alert(123)
}
}
}
});
const vm = app.mount('#root');
</script>
八、ref、reactive响应式引用的用法和原理、toRef以及context参数
<script>
// ref, reactive 响应式的引用
// 原理,通过 proxy 对数据进行封装,当数据变化时,触发模版等内容的更新
// ref 处理基础类型的数据
// reactive 处理非基础类型的数据
const app = Vue.createApp({
template: `
<div>{{name}}</div>
`,
setup(props, context) {
// const { ref } = Vue;
// proxy , 'dell' 变成 proxy({value: 'dell'}) 这样的一个响应式引用
// let name = ref('dell');
// setTimeout(() => {
// name.value = 'lee'
// }, 2000)
// return { name }
const { reactive, readonly, toRefs } = Vue;
// proxy , { name: 'dell'} 变成 proxy({ name: 'dell'}) 这样的一个响应式引用
const nameObj = reactive({name: 'dell', age: 28});
setTimeout(() => {
nameObj.name = 'lee'
}, 2000)
// toRefs proxy({ name: 'dell', age: 28}), {
// name: proxy({ value: 'dell'}),
// age: proxy({value: 28})
// }
const { name, age } = toRefs(nameObj);
return { name }
}
});
const vm = app.mount('#root');
</script>
九、使用Composition API开发Todolist
<script>
// 关于 list 操作的内容进行了封装
const listRelativeEffect = () => {
const { reactive } = Vue;
const list = reactive([]);
const addItemToList = (item) => {
list.push(item);
}
return { list, addItemToList }
}
// 关于 inputValue 操作的内容进行了封装
const inputRelativeEffect = () => {
const { ref } = Vue;
const inputValue = ref('');
const handleInputValueChange = (e) => {
inputValue.value = e.target.value
}
return { inputValue, handleInputValueChange}
}
const app = Vue.createApp({
setup() {
// 流程调度中转
const { list, addItemToList } = listRelativeEffect();
const { inputValue, handleInputValueChange} = inputRelativeEffect();
return {
list, addItemToList,
inputValue, handleInputValueChange
}
},
template: `
<div>
<div>
<input :value="inputValue" @input="handleInputValueChange" />
<button @click="() => addItemToList(inputValue)">提交</button>
</div>
<ul>
<li v-for="(item, index) in list" :key="index">{{item}}</li>
</ul>
</div>
`,
});
const vm = app.mount('#root');
</script>
十、computed方法生成计算属性
<script>
// computed 计算属性
const app = Vue.createApp({
setup() {
const { reactive, computed } = Vue;
const countObj = reactive({ count: 0});
const handleClick = () => {
countObj.count += 1;
}
let countAddFive = computed({
get: () => {
return countObj.count + 5;
},
set: (param) => {
countObj.count = param - 5;
}
})
setTimeout(() => {
countAddFive.value = 100;
}, 3000)
return { countObj, countAddFive, handleClick }
},
template: `
<div>
<span @click="handleClick">{{countObj.count}}</span> -- {{countAddFive}}
</div>
`,
});
const vm = app.mount('#root');
</script>
十一、watch 和 watchEffect 的使用和差异性
<script>
// watch 侦听器
// watchEffect 侦听器,偏向于 effect
const app = Vue.createApp({
setup() {
const { reactive, watch, watchEffect, toRefs } = Vue;
const nameObj = reactive({
name: 'dell', englishName: 'lee'
})
// 具备一定的惰性 lazy
// 参数可以拿到原始和当前值
// 可以侦听多个数据的变化,用一个侦听器承载
watch([() => nameObj.name, () => nameObj.englishName], ([curName, curEng], [prevName, preEng]) => {
console.log('watch', curName, prevName, '---', curEng, preEng);
}, { immediate: true })
// 立即执行,没有惰性 immediate
// 不需要传递你要侦听的内容,自动会感知代码依赖,不需要传递很多参数,只要传递一个回调函数
// 不能获取之前数据的值
// const stop = watchEffect(() => {
// console.log(nameObj.name);
// console.log(nameObj.englishName);
// setTimeout(() => {
// stop();
// }, 5000)
// })
const { name, englishName } = toRefs(nameObj);
return { name, englishName }
},
template: `
<div>
<div>
Name: <input v-model="name">
</div>
<div>
Name is {{name}}
</div>
<div>
EnglishName: <input v-model="englishName">
</div>
<div>
EnglishName is {{englishName}}
</div>
</div>
`,
});
const vm = app.mount('#root');
</script>
十二、生命周期函数的新写法
<script>
const app = Vue.createApp({
// beforeMount => onBeforeMount
// mounted => onMounted
// beforeUpdate => onBeforeUpdate
// beforeUnmount => onBeforeUnmount
// unmouted => onUnmounted
setup() {
const {
ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated,
onRenderTracked, onRenderTriggered
} = Vue;
const name = ref('dell')
onBeforeMount(() => {
console.log('onBeforeMount')
})
onMounted(() => {
console.log('onMounted')
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate')
})
onUpdated(() => {
console.log('onUpdated')
})
// 每次渲染后重新收集响应式依赖
onRenderTracked(() => {
console.log('onRenderTracked')
})
// 每次触发页面重新渲染时自动执行
onRenderTriggered(() => {
console.log('onRenderTriggered')
})
const handleClick = () => {
name.value = 'lee'
}
return { name, handleClick }
},
template: `
<div @click="handleClick">
{{name}}
</div>
`,
});
const vm = app.mount('#root');
</script>
十三、Provide,Inject,模版 Ref 的用法
<script>
// provide, inject
// dom ref
// const app = Vue.createApp({
// setup() {
// const { provide, ref, readonly } = Vue;
// const name = ref('dell');
// provide('name', readonly(name));
// provide('changeName', (value) => {
// name.value = value;
// });
// return { }
// },
// template: `
// <div>
// <child />
// </div>
// `,
// });
// app.component('child', {
// setup() {
// const { inject } = Vue;
// const name = inject('name');
// const changeName = inject('changeName');
// const handleClick = () => {
// changeName('lee');
// }
// return { name, handleClick }
// },
// template: '<div @click="handleClick">{{name}}</div>'
// })
// CompositionAPI 的语法下,获取真实的 DOM 元素节点
const app = Vue.createApp({
setup() {
const { ref, onMounted } = Vue;
const hello = ref(null);
onMounted(() => {
console.log(hello.value);
})
return { hello }
},
template: `
<div>
<div ref="hello">hello world</div>
</div>
`,
});
const vm = app.mount('#root');
</script>
十四、VueCLI 的使用和单文件组件
1.先安装node.js
2.node -v
3.安装npm、nrm、nrm ls
4.如果先前安装过脚手架,请先卸载再安装新的。
5.使用脚手架创建vue项目。
6.启动项目,浏览器查看端口。
App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
// 单文件组件
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
},
}
</script>
<style>
</style>
man.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<style>
</style>
十五、使用单文件组件编写 TodoList
Listitem.vue
<template>
<li class="button">{{ msg }}</li>
</template>
<script>
export default {
name: 'ListItem',
props: {
msg: String
}
}
</script>
<style>
</style>
App.vue
<template>
<div>
<input v-model="inputValue" />
<button class="button" @click="handleAddItem">提交</button>
</div>
<ul>
<list-item
v-for="(item, index) in list"
:key="index"
:msg="item"
/>
</ul>
</template>
<script>
import { reactive, ref } from 'vue';
import ListItem from './components/ListItem';
export default {
name: 'App',
components: { ListItem },
setup() {
const inputValue = ref('');
const list = reactive([]);
const handleAddItem = () => {
list.push(inputValue.value);
inputValue.value = '';
};
return { handleAddItem, inputValue, list }
}
}
</script>
<style>
.button {
margin-left: 20px;
color: red;
}
</style>
main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
十六、Vue-Router 路由的理解和使用
index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/about',
name: 'About',
// 异步加载路由
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
App.vue
<template>
<div id="nav">
<!-- router-link 是跳转路由的标签 -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/login">Login</router-link>
</div>
<!-- router-view 负责展示当前路由对应的组件内容 -->
<router-view/>
</template>
<style></style>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 路由是指根据 url 的不同,展示不同的内容
createApp(App).use(router).mount('#app')
十七、VueX的语法
router/ index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
store/ index.js
import { createStore } from 'vuex'
// VueX 数据管理框架
// VueX 创建了一个全局唯一的仓库,用来存放全局的数据
export default createStore({
state: { name: 'dell' },
// mutation 里面只允许写同步代码,不允许写异步代码
// commit 和 mutation 做关联
mutations: {
change(state, str) {
state.name = str;
}
},
// dispatch 和 actions 做关联
actions: {
// change(store, str) {
// setTimeout(() => {
// store.commit('change', str)
// }, 2000)
// }
}
})
About.vue
<template>
<div class="about">
<h1 @click="handleClick">This is an about page</h1>
<h1>{{myName}}</h1>
</div>
</template>
<script>
export default {
name: 'Home',
computed: {
myName() {
return this.$store.state.name;
}
},
methods: {
handleClick() {
// 1. dispatch 方法,派发一个 action,名字叫做change
// 2. 感知到 change 这个action,执行store 中 actions 下面的 change 方法
// 3. commit 提交一个叫做 change 的数据改变
// 4. mutation 感知到提交的change改变,执行 change 方法改变数据
this.$store.commit('change', 'hello world');
}
}
}
</script>
十八、CompositionAPI 中使用 VueX
store/ index.js
import { createStore } from 'vuex'
export default createStore({
state: { name: 'dell' },
mutations: {
changeName(state, str) {
state.name = str;
}
},
actions: {
getData(store) {
setTimeout(() => {
store.commit('changeName', 'hello')
}, 2000)
}
}
})
About.vue
<template>
<div class="about">
<h1 @click="handleClick">This is an about page</h1>
<h1>{{name}}</h1>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useStore } from 'vuex';
export default {
name: 'Home',
setup() {
const store = useStore();
const { name } = toRefs(store.state);
const handleClick = () => {
store.dispatch('getData')
}
return { name, handleClick }
}
}
</script>·
十九、使用axios发送ajax请求
index.js
import { createStore } from 'vuex'
import axios from 'axios';
export default createStore({
state: { name: 'dell' },
mutations: {
changeName(state, str) {
state.name = str;
}
},
actions: {
getData(store) {
axios.post('https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register')
.then((response) => {
const msg = response.data.message;
store.commit('changeName', msg)
})
}
}
})
About.vue
<template>
<div class="about">
<h1 @click="handleClick">This is an about page</h1>
<h1>{{name}}</h1>
</div>
</template>
<script>
// https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register
import { toRefs } from 'vue';
import { useStore } from 'vuex';
export default {
name: 'Home',
setup() {
const store = useStore();
const { name } = toRefs(store.state);
const handleClick = () => {
store.dispatch('getData')
}
return { name, handleClick }
}
}
</script>·