项目dome地址
vite
Vue3.0 && Vue3.0初体验 一 juejin.cn/post/684790…
安装
yarn create @vitejs/app
复制代码
vite.config.js
import {
defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
const path = require('path')
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
// 键必须以斜线开始和结束
"@": path.resolve(__dirname, "./src"),
}
},
base: './',
outDir: 'dist',
plugins: [vue()]
})
复制代码
环境配置
第一种:
yarn add cross-env -D
"scripts": {
"dev": "cross-env NODE_ENV=development vite",
"build": "cross-env NODE_ENV=development vite build",
"build": "cross-env NODE_ENV=production vite build",
"serve": "vite preview"
},
复制代码
第二种:
"scripts": {
"dev": "vite --mode development",
"build:uat": "vite build --mode staging",
"build:prd":"vite build --mode production",
"serve": "vite preview"
},
复制代码
# .env.development
NODE_ENV=development
VITE_APP_TITLE=My App (staging)
复制代码
# .env.staging
NODE_ENV=production
VITE_APP_TITLE=My App (staging)
复制代码
# .env.production
NODE_ENV=production
VITE_APP_TITLE=My App (staging)
复制代码
VITE_ 是必写
使用
let title = import.meta.env.VITE_APP_TITLE
复制代码
教程
setup 函数
setup 函数是一个新的Vue组件, 是Composition API 入口
<template>
</template>
<script>
import { setup } from 'vue'
export default {
setup(props, context) {
//这里的props大家应该知道是啥吧,父组件传的值
// context是什么?
//在setup()里我们不能用this
//所以vue2.0里的 this.$emit, this.$psrent, this.$refs在这里都不能用了。
//context就是对这些参数的集合
//context.attrs
//context.slots
//context.parent 相当于2.0里 this.$psrent
//context.root 相当于2.0里 this
//context.emit 相当于2.0里 this.$emit
//context.refs 相当于2.0里 this.$refs
...
}
}
</script>
<style>
</style>
复制代码
路由router / 路由参数route
import { useRouter, useRoute } from 'vue-router'
import { setup } from 'vue'
export default {
setup(props, context) {
// 获取参数
const route = useRoute()
const { id } = route.query
// 路由钩子函数
const router = useRouter()
router.beforeEach((to, from) => {
if (to.meta.index > from.meta.index) {
state.transitionName = 'slide-left' // 向左滑动
} else if (to.meta.index < from.meta.index) {
// 由次级到主级
state.transitionName = 'slide-right'
} else {
state.transitionName = '' // 同级无过渡效果
}
})
const onAdd = () => {
router.push({ path: '/address-edit', query: { type: 'add', from: state.from }})
}
return {
onAdd
}
}
}
复制代码
声明变量 ref reactive
ref 和 reactive 一样都是实现响应式数据的方法
- reactive 必须传递一个对象
- ref()
import { setup, Reactive, torefs } from 'vue'
export default {
setup(props, context) {
let count = ref(0) // ref(初始值) 无初始值设置为null
let name = ref('jeff')
const obj = reacttive({
data1: '123',
data2: {}
})
return {
count,
name,
...torefs(obj)// 把obj转为响应式的ref,不然template里获取不到
}
}
}
复制代码
Dom
<div class="search-wrap" ref="searchWrap">
</div>
import { onMounted } from 'vue'
export default {
setup() {
const searchWrap = ref(null)
onMounted(async () => {
let $screenHeight = document.documentElement.clientHeight
console.log('searchWrap.value', searchWrap.value)
searchWrap.value.style.height = $screenHeight - 100 + 'px'
})
return {
searchWrap
}
}
}
复制代码
nextTick
export default {
setup() {
nextTick(()=> {
})
}
}
复制代码
方法函数 method
在vue3.0没有methods方法
方法也要放在return 里面
export default {
setup() {
// 方法 一
const goToDetail = (item) => {
router.push({ path: `/product/${item.goodsId}` })
}
// 方法 二
const tips = () => {
Toast('敬请期待');
}
return {
goToDetail
tips
}
}
}
复制代码
components / props
写法vue 2.0一样
import ziComp from './ziComp.vue'
import { setup } from 'vue'
export default {
props: ['val'], //这里获取props和 2.0 一样,也可以用对象形式
components: {
ziComp
}, //components方法也是和2.0相同
setup(props, context) {
const value = ref(props.val)
const goBack = ()=> {
if (!props.val) {
// 处理
}
}
return {
value
goBack
}
}
}
复制代码
emit 事件
// 父级组件
<s-header :name="'生成订单'" @callback="deleteLocal"></s-header>
// 子级组件
<div>{{name}}</div>
export detault {
props: {
name: {
type: String,
default: ''
},
back: {
type: String,
detault: ''
}
},
emits: ['callback'],
setup(props, ctx) {
const goBack = () => {
if (!props.name) {
router.go(-1)
} else {
router.push({ path: props.back })
}
ctx.emit('callback')
}
return {
goBack
}
}
}
复制代码
watchEffect 监听 props
<template>
<div>{{obj.data1}}</div>
</template>
<script>
import { Reactive, watchEffect } from 'vue'
export default {
props: ['val'], //这里获取props和 2.0 一样,也可以用对象形式
setup(props, context) {
watchEffect(() => { //首次和props改变才会执行这里面的代码
console.log(props.val)
})
}
}
</script>
<style>
</style>
复制代码
watch() 监听器
import { Reactive } from 'vue'
export detault {
setup(props, context) {
let count = ref(0)
let state = reactive({
count2: 1
})
//监听ref类型
watch(count, (countNew, preCount)) => { //count新值, preCount旧值(count)
console.log('') //这里是监听数据变化后执行的函数
}
//监听reactive类型
watch(()=> state.count2, (count2New, preCount)=> {
console.log('') //这里是监听数据变化后执行的函数
}, {lazy: false}) // //在第一次创建不监听
}
return {
count
countNew,
count2New
...toRefs(state)
}
}
复制代码
监听多个数据
import { setup, Reactive } from 'vue'
export default {
setup(props, context) {
let count1 = ref(0)
let name1 = ref(0)
let state = reactive({
count2: 0,
name2: 'yangy'
)
//监听多个reactive类型
watch(
[() => state.count2, () => state.name2]
([count, name], [preCount, preName]) => { //count新值, preCount旧值
console.log('') //这里是监听数据变化后执行的函数
},
{
lazy: false
})//在第一次创建不监听
//监听ref类型
watch(
[count2, name2]
([count, name], [preCount, preName]) => { //count新值, preCount旧值
console.log('') //这里是监听数据变化后执行的函数
}, {lazy: false}//在第一次创建不监听)
return {
count,
...toRefs(state)
}
}
}
复制代码
computed()计算属性
可创建只读,和可读可写两种
import { setup, Reactive } from 'vue'
export default {
setup(props, context) {
let count = ref(0)
setup () {
const state = reactive({
list: []
})
const count = ref(0)
const addCount = computed(() => count.value + 1) //只读 ,count.value变化后执行加1
const addCount2 = computed({
get:() => count.value + 1,
set: (value) => count.value = value
})
// addCount2.value = 10 //赋值方法
const total = computed(() => {
let sum = 0
let _list = state.list.filter(item => state.result.includes(item.cartItemId))
_list.forEach(item => {
sum += item.goodsCount * item.sellingPrice
})
return sum
})
return {
total
count
addCount
addCount2
}
}
}
}
复制代码
script setup
<HelloWorld></HelloWorld>
<div @click='doClick'></div>
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import msg from "./components/msg.vue"
// props
import { defineProps, defineEmit } from "vue";// props emit
let props = defineProps({
msg: String,
});
let emit = defineEmit(['callback'])
// 事件
function doClick() {
}
// 获取上下文
import {useContext} from 'vue'
// 生命周期 和 声明
import { reactive, onMounted } from "vue";
const msg = ''
const state = reactive({
mag: "我爱祖国"
});
onMounted(()=> {
initData()
})
const initData = ()=> {
console.log(state.mag)
}
// 类似vue2.0的this, script setup中vue提供getCurrentInstance proxy
import { reactive, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const init = () => {
proxy.$alert('这是一段内容', '标题名称', {
confirmButtonText: '确定',
callback: action => {
proxy.$message({
type: 'info',
message: `action: ${ action }`
});
}
});
};
// 获取路由 和 路由参数
import { reactive, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const init = () => {
let { id } = proxy.$route.query
}
// 或者利用 useRoute useRouter
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
let { id } = route.query
</script>
复制代码
vue3生命周期
import { onMounted, onUpdated, onUnmounted } from 'vue'
复制代码
除去 beforeCreate
和 created
之外,在我们的 setup
方法中,有9个旧的生命周期钩子,我们可以在setup
方法中访问
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- onUnmounted
- onActivated
- onDeactivated
- onErrorCaptured
我们导入它们并在我们的代码中访问它们
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured } from 'vue'
export default {
setup() {
onBeforeMount(() => {
// ...
})
onMounted(() => { // 异步
// ...
})
onBeforeUpdate(() => {
// ...
})
onUpdated(() => {
// ...
})
onBeforeUnmount(() => {
// ...
})
onUnmounted(() => {
// ...
})
onActivated(() => {
// ...
})
onDeactivated(() => {
// ...
})
onErrorCaptured(() => {
// ...
})
}
复制代码
- beforeCreate -> use setup()
- created -> use setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
store状态管理
yran add vuex@4.0.0-beta.4
index.js
state.js
mutation.js
action.js
// index.js
import { createStore } from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
export default createStore({
state,
mutations,
actions,
modules: {}
})
// state.js
export default {
cartCount: 0
}
// mutation.js
export default {
addCart (state, payload) {
state.cartCount = payload.count
}
}
// action.js
import { getCart } from '../service/cart'
export default {
async updateCart(ctx) {
const { data } = await getCart()
ctx.commit('addCart', {
count: data.length || 0
})
}
}
复制代码
// main.js
import App from './App.vue'
import store from './store'
const app = createApp(App) // 创建实例
app.use(store)
app.mount('#app')
复制代码
页面中
import { useStore } from 'vuex'
export detault {
setup() {
const store = useStore()
onMounted(()=> {
store.dispatch('updateCart')
})
const handleAddCart = async () => {
store.dispatch('updateCart')
})
return {
handleAddCart
}
}
}
复制代码
vue-jsx
yarn add @vitejs/plugin-vue-jsx
// vite.config.js
import {
defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJxs from '@vitejs/plugin-vue-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), vueJxs()]
})
复制代码
// setup写法
<script lang='jsx'>
import { ref } from 'vue'
export default {
setup() {
let counter = ref(0)
let onclick = ()=> {
counter.value ++
}
return ()=> {
<>
<div>comp</div>
<p onClick={onclick}>{counter.value}</p>
</>
}
}
}
</script>
复制代码
mock数据
yarn add vite-plugin-mock -D
yarn add mockjs -S
// vite.config.js
// vite.config.js
import {
defineConfig
} from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJxs from '@vitejs/plugin-vue-jsx'
import { viteMockServe } from 'vite-plugin-mock';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), vueJxs(), viteMockServe({ supportTs: false })]
})
复制代码
在根目录新建mock
比如新建js文件,比如user.js
export default [
{
url: '/api/createUser',
method: 'post',
response: ({ body }) => {
console.log('body>>>>>>>>', body);
return {
code: 0,
message: 'ok',
data: null,
};
},
},
];
复制代码
role.js
export default [
{
url: '/api/getRoleById',
method: 'get',
response: ({ query }) => {
console.log('id>>>>>>>>', query.id);
return {
code: 0,
message: 'ok',
data: {
roleName: 'admin',
roleValue: 'admin',
},
};
},
},
];
复制代码
vue-router
yarn add vue-router@next -S
router/index.js
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
component: () => import("../views/index.vue"),
},
],
});
export default router
复制代码
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router/index";
const app = createApp(App)
app.use(router)
app.mount("#app");
复制代码
vuex
yarn add vuex@nest -S
// store/index.js
import { createStore } from 'vuex'
export detault createStore({
state: {
counter: 0
},
mutations: {
add(state)=> {
state.counter ++
}
}
})
复制代码
import { createApp } from "vue";
import App from "./App.vue";
import store from './store'
const app = createApp(App)
app.use(store)
app.mount("#app");
复制代码
<p @click="$store.commit('add')">
{{$store.state.counter}}
</p>
复制代码
样式管理
安装 sass
yarn add sass -D
@import './element-ui.scss'
@import './index.scss'
@import './mixin.scss'
@import './sidebar.scss'
复制代码
styles目录保存各种样式
element-ui.scss
index.scss
mixin.scss
sidebar.scss
打包build
yarn build
复制代码
构建打包后,直接在浏览器打开会报cors错误
直接放在服务器就不会报错,正常运行
npm install http-server -g
http-server [path] [options]
复制代码
直接进入打包后dist文件中,执行http-server
命令(默认8080)
直接打开http://127.0.0.1:8080/index.html#/