vite2 + vue3 项目简易入门和使用经验总结

项目dome地址

gitee.com/Jaction/vit…

vite

cn.vitejs.dev/

Vue3.0 && Vue3.0初体验 一 juejin.cn/post/684790…

安装

cn.vitejs.dev/guide/#scaf…

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() 声明单一基础数据类型时使用 blog.csdn.net/weixin_4329…
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'
 

除去 beforeCreatecreated 之外,在我们的 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-jsx'

// 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错误

直接放在服务器就不会报错,正常运行

blog.csdn.net/sayyy/artic…

npm install http-server -g

http-server [path] [options]
 

直接进入打包后dist文件中,执行http-server命令(默认8080)

直接打开http://127.0.0.1:8080/index.html#/

(0)
上一篇 2021年5月26日 下午5:15
下一篇 2021年5月26日 下午5:31

相关推荐

发表回复

登录后才能评论