vue3+ts+vite 项目

312 阅读2分钟

错误处理

1. ts提示vue组件找不到“找不到模块“./App.vue”或其相应的类型声明。ts(2307)

//原因 ts 无法理解 .vue 文件 解决方法在src目录下新建 shims-vue.d.ts文件

declare module '*.vue' {
    import { ComponentOptions } from 'vue';
    const componentOptions: ComponentOptions;
    export default componentOptions;
}

2. 安装sass后报错

“[vite] Dep optimization failed with error:

Could not load util (imported by node_modules/sass/sass.dart.js): ENOENT: no such file or directory, open 'D:\ji-rengu\zgnUI\util'“

// 解决方法 在package.json文件中 sass 应该放在 devDependencies 对象中

"devDependencies": {
    "sass": "^1.55.0",
    "@vue/compiler-sfc": "^3.0.4",
    "vite": "^1.0.0-rc.13"
  }

3. 引入 vue 模块报错

在项目中建立自定义的.d.ts声明文件只有打开了,vscode才会有代码提示,不打开就没有提示了

  • 解决方法:在项目根目录下新建一个jsconfig.json文件,重启vscode,就可以了

4. 不能将类型“() => void”分配给类型“MouseEvent” 可能是版本问题

解决方法:npm uninstall @types/node 卸载

重新安装:npm install @types/node@18.7.18 -D

5. ui库组件的css 不能加 scoped

原因:因为vue自动生成的样式名 data-v-xxx 是随机数,每次运行可能会发生变化

必须使用输出稳定不变的class选择器,方便使用者覆盖

注意:对于不想被用户覆盖的默认属性,属性名应该尽量复杂一些,太常用的单词容易被覆盖

解决方法: 为所有属性名加前缀

6. 动态挂载组件

import Dialog from './Dialog.vue'
import { createApp, h } from 'vue'
export const openDialog = (options) => {
    const { title, content, ok, cancel } = options
    const div = document.createElement('div')
    document.body.appendChild(div)
    const app = createApp({
        render() {
            return h(
                Dialog, //组件名
                //------------组件参数
                {
                    visible: true,
                    'onUpdate:visible': (newVisible) => {
                        if (newVisible === false) {
                            app.unmount(div);
                            div.remove();
                        }
                    },
                    ok, cancel
                },
                //-----------------
                { title: title, content: content })
        }// 插槽     			
    })
    app.mount(div)
}

7. 获取子组件属性和内容

  • 如何获取组件内子组件的内容,属性,利用vue3 setup(props,ctx) ****ctx 可以获取上下文
<template>
  <div>
    <!--动态子组件 -->
    <component :is="defaults[0]"></component>
    <component :is="defaults[0]"></component>
  </div>
</template>

<script>
  import Tab from './Tab.vue'
  // 组件最后会被vue3 渲染成一个对象,可以通过上下文的slots.default()获取到
  export default {
    setup(props,ctx){
      const defaults = ctx.slots.default() // 这句代码可以获取内部子组件的内容
      defaults.forEach(item => {
      	if(item.type!==Tab){
        	throw new Error('Tabs 子组件必须是Tab')
        }
    	})
      return {
        defaults
      }
    }
  }
</script>

8、动态获取 div 元素的宽度和位置

重点:使用vue获取 v-for 遍历创建的每一个子组件

<!--通过绑定ref属性,判断el即当前组件,index是遍历的key,navItems是提前声明好的数组用来保存组件数据  -->
<template>
  <div :ref="el=>{if(el) navItems[index]=el}"></div>
</template>

<script lang='ts'>
import {ref} from 'vue'
  setup(props,ctx){
  	const navItems = ref<HTMLDivElement[]>([])
    onMounted(() => {
    	const divs=navItems.value
      const result = divs.filter(div=>div.classList.contains('selected'))[0]
       result.getBoundingClientRect()//获取div 宽度
      console.log(result)//result就是被选中的元素
    })
    // 可以通过navItems.value 获取数组中保存的数据
    return {navItems}
  }  
</script>

9、封装input组件

<!-- input组件 -->
<template>  
	<div class="zgn-textInput-wrapper">
    <main class="zgn-texInput">
      <input class="zgn-textInput-input" 
             type="text" :placeholder="placeholder"
             :value="inputContent"
              @input="setContent"/>
      <div class="zgn-textInput-nav">
        <div></div>
        <div>
          <Button theme="button" @click="cancel">取消</Button>
          <Button theme="button" purpose="yes" @click="ok">确认</Button>
        </div>  
      </div>
		</main>
  </div>
</template>

<script>
import Button from './Button.vue'
import {ref} from 'vue'
export default {
    components:{Button},
    props:{
        placeholder:{
            type:String,
            default:'请在此输入内容'
        },
        inputContent:{
            type:String,
            default:''
        },
    },
    setup(props,ctx){
        const setContent=(e)=>{
            ctx.emit('update:inputContent',e.target.value)
        }
        // const ok=()=>{
        //     if(props.ok && props.ok()!== false){
        //         close()
        //     }
        // }
        // const cancel=()=>{
        //     props.cancel()
        //     close()
        // }
        // const close=()=>{
        //     ctx.emit('update:visible',false)
        // }
        // return{ ok,close,setContent,cancel}
    }        
}
</script>

<!-- 父组件 -->
<template>
    <div>
        <TextInput placeholder="你好" v-model:inputContent="inputContent" 
        v-model:visible="visible" :ok="fn1" :cancel="fn2">
        </TextInput>
        {{inputContent}}
    </div>
    <Button theme="button" @click="setVisible">显示</Button>
</template>

<script>
import TextInput from "../lib/TextInput.vue"
import Button from '../lib/Button.vue'
import {ref} from 'vue'    
export default {
    components:{TextInput,Button},
    setup(){
        const inputContent = ref('')
        const visible = ref(false)
        const setVisible=()=>{
            visible.value=!visible.value
        }
        const fn1=()=>{
            console.log('this is fn1')
        }
        const fn2=()=>{
            console.log('this is fn2')
        }
        return {inputContent,visible,setVisible,fn1,fn2}
    }
}
</script>

10、html 标签 转 markdown 样式

www.npmjs.com/package/git… github-markdown-css

11、直接在页面中引用Markdown文档

  • vite 插件

10、CSS 相关

媒体查询

@media (max-width:500px) {
  >.menu{display: none;}
}
/* @media( 条件 ){ 满足条件执行的样式 } */

渐变背景

css Gradient 网站可以自动生成渐变色代码

sass 用法

fade-out($color: #000000, $amount: 0.95)

cursor: pointer;
  
[class^="zgn-"],[class*="zgn-"] {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}