success: (res: GetStorageSuccess) => {
const list = JSON.parseArray
- (res.data as string)
if (list != null) {
this.list = list
现在获取JSON.parseArray(res.data as string)这样就行 以前的写法是:JSON.parseArray<Item>(JSON.stringify(res.data))
const emits = defineEmits<{ (event: 'reply', obj: ReplyEmit): void }>();
function reply() {
const data: ReplyEmit = { id: '123', message: 'Hello, World!' };
emits('reply', data);
//下面是父组件
<MyComponent @reply="handleReply" />
methods: {
handleReply(obj) {
console.log(obj.id); // '123'
console.log(obj.message); // 'Hello, World!'
类型声明 { (event: 'reply', obj: ReplyEmit): void }
这里使用了 TypeScript 的函数类型定义,描述了这个组件可以触发的事件及其参数类型。
event: 'reply':指定该组件可以发射一个名为 'reply' 的事件。这个事件名称是字符串类型 'reply',表示在使用组件时,父组件可以监听 reply 事件。
obj: ReplyEmit:reply 事件的第二个参数是 obj,类型为 ReplyEmit。这意味着触发 reply 事件时,会传递一个类型为 ReplyEmit 的对象。这个对象类型 ReplyEmit 需要在你的代码中定义好,可以包含你需要传递的具体数据。
void:表示这个函数没有返回值,即触发事件后不会有返回值给调用者。
onLoad 必须有参数 没有的话会报错,还要放在script最下面,不然容易找不到某些方法
箭头函数必须有大括号
// 从响应式 proxy 创建的只读 proxy
const stateCopy = readonly(state)
console.log(isReactive(stateCopy)) // -> true
function useState<State extends string>(initial: State) {
const state = ref(initial) as Ref<State> // state.value -> State extends string
return state
<span>{{ count }}</span>
<button @click="count ++">Increment count</button>
<button @click="nested.count.value ++">Nested Increment count</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return {
count,
nested: {
count
</script>
let { author, title } = toRefs(book)
title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'
function useFoo(x: number | Ref<number>) {
const unwrapped = unref(x) // unwrapped 现在一定是数字类型
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo')) // 把props继承的对象中的foo属性传入useSomeFeature这个函数。
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
export default {
setup() {
return {
text: useDebouncedRef('hello')
watch(counter, (newValue, oldValue) => {
console.log('The new counter value is: ' + counter.value)
// 到最后要讲里面写的方法和变量return回来
return {a}
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted, watch, toRefs, computed } from 'vue'
// in our component
setup (props) {
// 使用 `toRefs` 创建对 props 中的 `user` property 的响应式引用
const { user } = toRefs(props)
const repositories = ref([])
const getUserRepositories = async () => {
// 更新 `props.user ` 到 `user.value` 访问引用值
repositories.value = await fetchUserRepositories(user.value)
onMounted(getUserRepositories)
// 在用户 prop 的响应式引用上设置一个侦听器
watch(user, getUserRepositories)
const searchQuery = ref('')
const repositoriesMatchingSearchQuery = computed(() => {
return repositories.value.filter(
repository => repository.name.includes(searchQuery.value)
return {
repositories,
getUserRepositories,
searchQuery,
repositoriesMatchingSearchQuery
attrs 和 slots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.x 或 slots.x 的方式引用 property。
请注意,与 props 不同,attrs 和 slots 是非响应式的。
如果你打算根据 attrs 或 slots 更改应用副作用,那么应该在 onUpdated 生命周期钩子中执行此操作
执行 setup 时,组件实例尚未被创建。因此,你只能访问以下 property:
props
attrs
slots
换句话说,你将无法访问以下组件选项:
computed
methods
注意,从 setup 返回的 refs 在模板中访问时是被自动解开的,因此不应在模板中使用 .value
setup 还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:
// MyBook.vue
import { h, ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// Please note that we need to explicitly expose ref value here
return () => h('div', [readersNumber.value, book.title])
setup() {
const ButtonCounter = resolveComponent('button-counter')
return () => h(ButtonCounter)
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { MyButton } from '@/components'
export default defineComponent({
components: {
MyButton
props: {
name: String
setup() {
const count = ref(0)
const inc = () => count.value++
return {
count,
<script>
<script setup lang="ts">
import { defineComponent, ref, defineProps } from 'vue'
import { MyButton } from '@/components'
defineProps<{
name:string
const count = ref(0)
const inc = () => count.value++
<script>
watch([() => state.listParam.customerName, () => state.listParam.mainFollower],
([newCustomerName, newMainFoller],[oldCustomerName,oldMainFoller]) => {
state.listParam.customerName = newCustomerName.trim()
state.listParam.mainFollower = newMainFoller.trim()
immediate: true
return {
…toRefs(state) // 三点运算符实现多个返回
await语法支持
在script setup内可以直接使用await语法:
<script setup>
const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>
interface DebuggerOptions {
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
vue文件
<el-form :model="listParam" label-position="left" inline>
<el-form-item prop="searchKey">
<el-input v-model="listParam.searchKey" placeholder="请输入关键字" clearable size="small"></el-input>
</el-form-item>
<el-form-item prop="mainFollower">
<el-input v-model="listParam.mainFollower" placeholder="请输入跟进人姓名" clearable size="small"></el-input>
</el-form-item>
</el-form>
watchEffect(() => {
state.listParam.searchKey = state.listParam.searchKey ? state.listParam.searchKey.trim() : ""
state.listParam.mainFollower= state.listParam.mainFollower? state.listParam.mainFollower.trim() : ""
return {
...toRefs(state)
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
watch(() => state.listParam.searchKey, (newVal,oldVal) => {
console.log(newVal, oldVal)
state.listParam.searchKey = newVal.trim()
return {
...toRefs(state)
watch([() => state.listParam.customerName, () => state.listParam.mainFollower],
([newCustomerName, newMainFoller],[oldCustomerName,oldMainFoller]) => {
state.listParam.customerName = newCustomerName.trim()
state.listParam.mainFollower = newMainFoller.trim()
immediate: true
return {
...toRefs(state)
// 参见 `watchEffect` 共享选项的类型声明
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // 默认:false
deep?: boolean
var that = this
this.$echarts.registerMap('hunan', hunan); // 取数据
var myChart = this.$echarts.init(this.$refs.hunan_map)
var data = json.data;
var series = [];
// 画线,点的函数
var convertLineData = function (data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var dataItem = data[i];
var coordS = dataItem.lineS; // 线起点
var coordM = dataItem.lineM; // 线中间点
var coordE = dataItem.lineE; // 线尾点
if (coordS && coordM && coordE) {
res.push({
coords: [coordS, coordM, coordE]
return res;
var convertValData = function (data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var dataItem = data[i];
res.push({
name: dataItem.areaName,
value: dataItem.lineE.concat(dataItem.value)
return res;
// 这里是你要在地图上画的点,线配置,往data里面加就行
var json = {
data: [{
areaName: '长沙市',
value: 94,
lineS: [113.482279,28.19409],
lineM: [113.441, 28.4242],
lineE: [113.8648, 29.2891]
series.push(
{ // 这是画的线配置
name: '',
type: 'lines',
zlevel: 2,
symbol: 'none',
// silent: true, //不响应鼠标点击或事件
effect: {
show: false // 关闭特效
tooltip: {
show: false
labelLayout: {
draggable: true
polyline: true, // 支持多点连线
itemStyle:{
normal:{
lineStyle:{
width: that.nowSize(2),
type:'dotted' //'dotted'虚线 'solid'实线
lineStyle: {
normal: {
color: 'green',
opacity: 0.9,
curveness: 0
data: convertLineData(data)
{ // 这里是点还有点旁边的内容
name: '',
type: 'scatter',
coordinateSystem: 'geo',
zlevel: 2,
hoverAnimation: false, // hover时不高亮点
cursor: 'default', // 鼠标设置为箭头
itemStyle: {
normal: {
color: 'red'
tooltip: {
show: false,
label: {
rich: {
//自定义样式a
fontFamily: 'lcd', //字体名称
color: '#fff', //字体颜色
fontSize: that.nowSize(12), //字体大小
borderColor: 'rgba(30, 157, 222, 1)',
borderWidth: that.nowSize(1.2),
padding: [8, 8, 8, 8]
//**自定义样式b**
color: '#fff',
fontSize: 16
// normal: {
show: true,
position: 'right',
fontSize: that.nowSize(14),
fontWeight: 'bold',
color: '#f5a623',
formatter: function (param) {
return '{a|' + param.value[2] + '/工单' + '}' // 此处用到自定义样式
data: convertValData(data)
var option = { // 这里是地图内容配置
// backgroundColor: '#404a59', // 背景色
title: {
text: '全省人工服务概况',
left: 'center',
textStyle: {
color: '#2b9de0',
fontSize: that.nowSize(18)
tooltip: {
trigger: 'item'
legend: {
show: false,
selectorLabel: {
backgroundColor: 'black'
geo: {
map: 'hunan',
label: {
color: 'black',
fontSize: that.nowSize(14),
emphasis: {
show: true,
color: 'green',
areaColor: 'yellow'
roam: false,
selectedMode: 'single',
itemStyle: {
areaColor: 'red',
normal: {
// areaColor: 'black', // 地图整体的颜色
borderColor: '#404a59' // 边缘线颜色
emphasis: {
itemStyle: {
areaColor: 'red' // hover 的背景色
select: [{
itemStyle: {
areaColor: 'black' // hover 的背景色
regions: [{ // 默认选择
name: val.name,
selected: true,
itemStyle: {
normal: {
areaColor: '#AADDFF'
// areaColor: 'red', // 地图背景色
// backgroundColor: 'black',
// opacity: 0
series: series
myChart.setOption(option); // 应用配置
// 加个点击事件
myChart.on('click', function (e) {
// e.color = '#d50000'
if (e.hasOwnProperty('region')) {
option.geo.regions[0].name = e.region.name
myChart.setOption(option);
} else {
return false;
console.log(e.region,option)
建议线画地图出来,再一步步移植代码。
线,点或者其它什么样式基本都是label里面能改,字体样式什么的就是itemStyle里面改。
反正2个互相用就能解决大部分问题
最后formatter是个很有用的东西,在这是编辑点右边的数据。你们可以自己定义。
最后放个echart文档地址
https://echarts.apache.org/zh/option.html#title
const app = getApp();
const userInfo = app.globalData.userInfo;
console.log(userInfo); // 输出: { id: 123, name: ‘Alice’ }
3. 本地存储传值 ( 适用于需要跨页面、甚至跨应用会话的数据传递。 )
uni.setStorageSync('userInfo', { id: 123, name: 'Alice' });
uni.navigateTo({
url: '/pages/detail/detail'
//接受页面
onLoad() {
const userInfo = uni.getStorageSync('userInfo');
console.log(userInfo); // 输出: { id: 123, name: 'Alice' }
```javascript
import eventBus from '@/eventBus';
eventBus.$emit('sendUserInfo', { id: 123, name: 'Alice' });
uni.navigateTo({
url: '/pages/detail/detail'
**接收值页面:**
```javascript
import eventBus from '@/eventBus';
onLoad() {
eventBus.$on('sendUserInfo', (userInfo) => {
console.log(userInfo); // 输出: { id: 123, name: 'Alice' }
let a=document.createElement('a')
a.style.display = 'none'
a.setAttribute('download', 'bg.jpg')
a.href = require('@/assets/bg.jpg')
document.body.appendChild(a)
console.log('href', a.href)
a.click()
document.body.removeChild(a)
后端传的话需要调用get接口。
其它文件类型下载基本都是一样的 调用后端get接口,使用blob类型
responseType: ‘blob’。进行下载
注意:如果要是本地下载一些静态资源(除图片外) 资源要放在public目录文件下,不然打包后路径你会发现很多报错,下载找不到路径。@这个不会被解析。
附下载代码:
async download(){
console.log(this.urlName)
let res = await axios.get(`jt/${this.urlName}`, { responseType: 'blob' })
const url = window.URL.createObjectURL(res.data)
const link = document.createElement('a')
link.href = url;
link.setAttribute('download', `${this.urlName}`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
jt/${this.urlName}
jt是public下的一个文件夹, this.urlName是你要下载的文件的名字。
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>lesson 31</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<div id="root"></div>
</body>
<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>
</html>
state 存放状态
mutations state成员操作(处理数据,更改保存到state中。用法this.$store.commit )
getters 加工state成员给外界
actions 异步操作(一般用于处理请求逻辑之后将数据给mutations,用法this.$store.dispatch )
modules 模块化状态管理
modules 的每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
简单基础使用就不说了,说重点。
在项目中一般是以模块化管理为主。为了方便每个模块的管理和维护大多使用modules模块化状态管理。
import getters from './getters'
import actions from './modules/actions'
import mutations from './modules/mutation'
import user from './modules/user.js'
import user2 from './modules/user2'
import state from './store'
Vue.use(vuex)
export default new vuex.Store({
getters,
state,
//模块vuex
modules: {
//公共vuex2个模块
actions,
mutations,
//各个单独模块使用的vuex
user,
user2
使用modules后外面不要再加actions和mutations(会报错)
上其中一个单独模块的代码
//这里是user.js的代码
//某个模块专门使用的vuex。调用时加上该模块名字。如this.$store.commit('user/方法名')
const state = {
userName:''
const getters = {
userName:(state) => state.userName
const actions = {
add_name({commit},name){
commit('ADD_NAME',name);
console.log('这里是user1的actions',name)
const mutations = {
ADD_NAME(state,name){
state.userName=name;
console.log('这里是user1',name)
return true;
export default {
namespaced: true, //记住一定要加这个
state,
getters,
actions,
mutations
namespaced是告诉vuex给它搞个看见出来。默认false. 开启后就是提示打开了命名空间。这样2个模块有同样的方法也不会报错。
当你要调用某个模块的方法时记得写法是
this.$store.commit(‘模块名/方法名’)
this.$store.dispatch(‘模块名/方法名’)
一切弄完之后记得挂载到main.js上
import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'
import store from './store/index'
Vue.config.productionTip = false
Vue.use(Vuex)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, //这就是挂载了
components: { App },
template: '<App/>'
有时候报错说未找到该模块有这个方法
报错信息为:
[vuex] unknown action type: user/add_name
你可以删除命名空间试试。
下面放其他js的代码
//actions.js代码
//公共actions异步方法
export default {//在action中可以进行异步操作。
namespaced: true,
actions:{
add_book({commit},book){
commit('ADD_BOOK',book);
delete_book({commit},book){
commit('DELETE_BOOK',id);
//mutations.js代码
//公共mutation方法
export default {//这里要注意不要在mutations里面进行异步操作
namespaced: true,
mutations:{
ADD_BOOK(state,book){
state.bookList.push(book);
return true;
DELETE_BOOK(state,id){
bar = 'hello';
baz: boolean;
// error,Property 'baz' has no initializer and is not definitely assigned in the constructor
constructor() {
this.foo = 42;
有两种情况下我们不可避免该error的产生:
- 该属性本来就可以是 undefined 。这种情况下添加类型undefined
- 属性被间接初始化了(例如构造函数中调用一个方法,更改了属性的值)。这种情况下我们可以使用 显式赋值断言 (修饰符号 !) 来帮助类型系统识别类型。后面具体介绍它,先看下代码中怎么使用:
class StrictClass {
// …
baz!: boolean;
// ^
// 注意到这个!标志
// 代表着显式赋值断言修饰符
}
显式赋值断言(Definite Assignment Assertions)
尽管我们尝试将类型系统做的更富表现力,但我们知道有时用户比TypeScript更加了解类型
跟上面提到的类属性例子差不多,我们无法在给一个值赋值前使用它,但如果我们已经确定它已经被赋值了,这个时候类型系统就需要我们人的介入
let x: number;
initialize();
console.log(x + x);
// ~ ~
// Error! Variable 'x' is used before being assigned.
function initialize() {
x = 10;
添加 ! 修饰:let x!: number
,则可以修复这个问题
我们也可以在表达式中使用!,类似 variable as string
和 <string>variable
:
let x: number;
initialize();
console.log(x! + x!); //ok
function initialize() {
x = 10;
下面是一些小代码记录
关于类的继承
在父级类和子级类中一定要写一个constructor函数,如:
// 父级
class Parent{undefined
name:string;
age:number;
constructor(name:string,age:number){undefined
this.name = name;
this.age = age;
// 子级
class Web extends Tparent{undefined
constructor(name:string){undefined
this.name = name;
这个里面要放父级有的所有变量,这样子级才能拿得到。不然会报错。
static是静态内容
访问修饰符
public是共有内容,默认 例子:public name:string;
private是私有内容,私有属性无法继承和访问 例子: private name:string;
// 通过关键字interface来声明接口
interface laberValue{undefined
laber:string;
// 指定类型为接口类型
function printLaber(laberValue:laberValue) {undefined
console.log(laberValue.laber)
var myobjs = {laber:'hellos rouse'}
printLaber(myobjs)
// 接口的数组类型
interface StringArray{undefined
//[index:number]这是下标
[index:number]:string;
var myArray:StringArray;
myArray=["fuck","any","www",""];
console.log(myArray[1]);
// 接口的class的类型,对类的约束
interface ClockInterface{undefined
currentTime:string;
// void:不需要返回值
setTime(d:string):void;
class Clock implements ClockInterface{undefined
currentTime:string;
setTime(){undefined
console.log('tag '+this.currentTime);
constructor(currentTime:string){undefined
this.currentTime=currentTime;
var dsq=new Clock('jacks');
dsq.setTime();
// 接口的继承和混合类型
interface Shape{undefined
color:string;
interface PenStroke{undefined
penWidth:number;
interface Square extends Shape,PenStroke{undefined
sideLength:number;
// 泛型<T>,这个T你可以任意指定其他内容,如:<K>
// function Hellopes(num:number):number {undefined
// return num;
function Hellopes<T>(num:T):T {undefined
return num;
// 当你使用时需要什么类型就设置什么类型<类型>
var output = Hellopes<string>("hello,jack");
console.log(output)
var listers:Array<string>=Hellopll<string>(["1","2","3"]);
for(var i=0;i<listers.length;i++){undefined
console.log(listers[i]);
Module
解释:主要是把类,接口都定义在一个module中,方便维护和编写,避免出错
// module,每个类和接口要加export
module Validition{undefined
export interface StringValidator{undefined
isAccept(s:string):boolean;
var letterRegxp = /^[A-Za-z]+$/;
var numberRegxp = /^[0-9]+$/;
export class letters implements StringValidator{undefined
// 复写函数
isAccept(s:string):boolean{undefined
return letterRegxp.test(s);
export class ZipCodeVailed implements StringValidator{undefined
isAccept(s:string):boolean{undefined
return s.length === 5 && numberRegxp.test(s);
// 泛型的类型
function Heoo<T>(arg:T):T{undefined
return arg;
// 箭头函数意义(arg:K)的函数返回值类型为K
var myhello:<K>(arg:K)=>K=Heoo;
// 因为它本身自带类型检查,所以上诉代码可以简写为:var myhello=Heoo;
console.log(myhello("heoooooo"));
// 调用时定义类型
interface Hellp{undefined
<T>(arg:T):T;
function myHellp<T>(arg:T):T{undefined
return arg;
var MH:Hellp = myHellp;
// MH后面可以接类型,也可以不接,直接写MH("这是函数")
console.log(MH<string>("这是在调用时定义的泛型"));
// 定义接口时定义类型
interface Hellw<T>{undefined
(arg:T):T;
function eee<T>(arg:T):T{undefined
return arg;
var qeew:Hellw<string>=eee;
console.log(qeew("这是在接口定义了泛型"));
var myHelloNumber = new HelloNumber<number>();
myHelloNumber.zeros = 10;
myHelloNumber.add =(x,y)=>x+y
console.log(myHelloNumber.zeros)
console.log(myHelloNumber.add(1,5))