通过本文的50个web示例你将学到:

  • Vue3外围根底语法和进阶语法
  • less外围根底语法和进阶语法
  • scss外围根底语法和进阶语法

1.Expanding Cards

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

  • Vue ref办法定义根本响应式变量。如:
const currentIndex = ref(0);

ref办法当然也能够定义一个对象,然而通常定义对象应该应用reactive办法。

  • Vue v-for指令渲染列表。如:
v-for="(item,index) in imageItems" 

v-for指令渲染时最好指定key属性,不便虚构DOM Diff算法比对。

  • Vue 动静绑定class与style。如:
:class="index === currentIndex ? 'active' : ''":style="{ backgroundImage:`url(${ imageURL + item })`}"

:class:style代表设置动静类名和动静行内款式,其中:v-bind的简写,值能够是一个javascript表达式,如三元表达式,或者是对象,又或者是数组。

  • Vue 事件绑定。如:
@click="currentIndex = index"

vue事件能够简写为@ + 事件名,值为一个javascript表达式或者是一个函数。

less

  • 定义公共款式
.base-flex {    display: flex;    justify-content: center;    align-items: center;}//应用形式.app {    .base-flex;}
  • 嵌套语法
.app {    //...这里写外围款式    .ec-panel {        //...这里写外围款式    }}

less定义变量是@ + 变量名,如:

@width: 100px;
  • &

该符号示意对父选择器的一个援用,例如:

.ec-panel {    //...外围款式    &.active {        //...外围款式    }}

其中&.active其实就是.ec-panel.active的写法。

2. Progress Steps

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

通过defineProps定义props,如:

const props = defineProps({    width:{        type:Number,        default:350    },    progressWidth:{        type:Number,        default:0    }})

通过computed办法定义计算属性:

const styleWidth = computed(() => props.width+'px');

仍然是通过slot标签定义插槽:

<div class="ps-step-container">    <div class="ps-step-progress"></div>    <slot></slot></div>

通过defineEmits办法定义事件传递:

  • defineEmits注册事件名,办法通常是一个数组,传递多个事件名
  • 调用办法的返回值,而后将该事件向上传递
const emit = defineEmits(["on-click"]);const changeActive = () => {    emit("on-click");}

通过reactive定义响应式对象,它与ref办法的区别就是,通常咱们应用ref办法来定义根本数据类型,而reactive办法则是定义多个对象:

const bool = ref(false);const state = reactive({    status: false,    list:[        {            label:"测试值",            value:1        }    ]})

浏览器控制台花式玩法:

console.log("%c " + consoleText,"background:#0ca6dc;padding:4px 10px;border-radius:3px;color:#fff");

less

动静绑定款式变量的写法有两种,第一种则是字符串属性名,第二种则是间接写变量名:

width:v-bind("styleWidth");width:v-bind(styleProgressWidth);

::focus-visible选择器,示意键盘伪类焦点选择器,在标准中定义为:元素聚焦,同时浏览器认为聚焦轮廓应该显示。

有时候咱们心愿键盘触发聚焦轮廓,而鼠标关注焦点则不触发轮廓,此时用以下一行CSS代码搞定。

:focus:not(:focus-visible) {    outline: 0;}

属性选择器语法:

[属性选择器] {    //CSS款式}//如:[disabled] {    background-color: @color;    color: @font_color;    cursor: not-allowed;}

其它知识点同后面示例。

3. Rotating Navigation Animation

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

v-if与v-else指令,示意条件,v-html示意渲染html:

<div class="rna-page-content">    <slot>        <template v-if="props.isRenderHTML">            <p v-html="content"></p>        </template>        <template v-else>{{ props.content }}</template>    </slot></div>

typescript

typescript 定义接口通过interface关键字,就像定义对象一样,其后跟属性名:属性类型,如:

定义根本类型就是:类型值,如:

const URL: string = "";//代表URL是一个字符串类型
interface NavItemType {    url:string;    text:string;    icon:string;}

typescript泛型,如:

Array<NavItemType>

就代表是一个泛型,也就是数组类型,并且数组项的值应该是类型NavItemType,所以数据格式就应该相似如下:

export const navList = [  {    url: "http://www.eveningwater.com/",    text: "集体网页",    icon:"Website"  },  {    url: "https://www.eveningwater.com/my-web-projects/",    text: "我的我的项目",    icon:"project"  },  {    url: "http://github.com/eveningwater",    text: "github",    icon:"github"  },];

再如:

Array<string> //示意定义一个字符串数组

导出多个模块语法:

export { default as Content } from "./Content.vue";export { default as Menu } from "./LeftMenu.vue";export { default as NavList } from "./NavList.vue";

示意将三个组件的默认模块更名为对应的名字。

less

:deep深度选择器,相似于vue2的>>>和/deep/,通常用于影响子组件的款式,也就是因为加了scoped组件只作用在以后组件,而无奈作用到子组件,也就须要应用该选择器:

:deep(p) {    text-indent: 2em;    color:@content_font_color;    line-height: 2;    margin-bottom: 15px;    letter-spacing: 1px;}

动静款式拜访数组变量,能够依据索引来拜访,就像拜访数组元素一样:

background-image: v-bind("beforeResourceURL[0]");

css同级元素选择器,如:

& + .rna-nav-list ul {    transform: translateX(15px);    & .rna-nav-item {       transform: translateX(0);       transition-delay: .4s;    }}

示意选中以后选择器的兄弟选择器.rna-nav-list。

其它知识点同后面示例。

4. hidden-search-widget

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

给元素或者是组件绑定ref,能够拜访组件或者元素的理论DOM元素,例如:

const inputRef = ref(null);

watch办法,承受三个参数,第一个参数示意监听的数据,能够是一个函数,也能够是一个变量,或者也能够是一个监听的字符串属性名,第二个参数则是一个回调函数,能够获取到监听的值,第三个参数示意监听的配置对象,如深度监听deep属性。如:

watch(isActive,val => {    const inputElement = inputRef.value;    if(val && inputElement){        (inputElement as HTMLInputElement).focus();    }});

typescript

as 关键字能够将任意变量断言成任意类型,通常如果转换类型不对能够先强制转换成unknown,而后再转换成对应的类型。例如:

//假如inputElement不能被断言成HTMLInputElement类型,就须要先转换成unknowninputElement as unknown as HTMLInputElement

或者也能够间接断言成any。如:

inputElement as any 

尽管这样做能够回避ts的类型查看,但如无必要,尽量少应用as关键字断言变量的类型。

模板绑定:

<input type="text" class="hsw-input" ref="inputRef" :placeholder="props.placeHolder" />

其它知识点同后面示例。

5. blurry loading

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

一个工具函数,示意转换数字范畴的工具函数,感觉很罕用,能够记下来:

// https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbersexport const scale = (n:number,inMin:number,inMax:number,outerMin:number,outerMax:number) => (n - inMin) * (outerMax - outerMin) / (inMax - inMin) + outerMin;

typescript

Ref类型也是一个泛型,当然这里其实应该如此来定义setTimeout的返回值,而不应该应用any:

const timer:Ref<any> = ref(null);

应该批改成:

const timer:Ref<ReturnType<typeof setTimeout>> = ref(null);

typeof setTimeout示意获取setTimeout函数的类型,而ReturnType是typescript的内置类型,示意返回值的类型,联合起来就代表是setTimeout函数的返回值。

onMounted和onUnmounted是vue生命周期的钩子函数,别离代表组件挂载后和组件卸载后,承受一个回调函数作为参数,而后在回调函数当中执行相应的操作。

onMounted(() => {    //这里写逻辑});onUnmounted(() => {   //这里写逻辑})

less

获取对象值的变量作为款式,能够应用字符串和点语法获取,如:

opacity: v-bind("props.number");

其它知识点同后面示例。

6. scroll animation

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

函数节流,就是利用提早定时器,联合工夫戳来调用给定的函数。在这个函数外面也波及到了typescript泛型,任意类型,函数类型,并且也波及到了apply办法的应用,apply传入一个this对象,后续的参数则是一个数组。

export function throttle(fn:(...args:any []) => any,delay:number){    let timer:ReturnType<typeof setTimeout> | null = null,last:number = 0;    return function<T>(this:(...args:any []) => any,...args:Array<T>) {        let now = +new Date();        if(last && now < last + delay){            clearTimeout(timer);            timer = setTimeout(() => {                last = now;                fn.apply(this,args);            },delay);        }else{            last = now;            fn.apply(this,args);        }    }}

typescript

PropType类型,是一个泛型,用于定义prop的类型。如:

props:{    title:{        type:String as PropType<string>    },    content:{        type:String as PropType<string>    }},

setup函数为vue3的入口,也是一个生命周期钩子函数,相当于vue2的beforeCreate和created的合并。第一个参数能够获取到props,第二个参数是以后上下文,能够通过对象构造的形式获取emit,slots等。如:

setup(props,{ slots }){    const renderTitle = () => slots.title ? slots.title() : props.title;    const renderBoxContent = () => slots.default ? slots.default() : props.content;    return () => (        <div class="scroll-ani-box">            <Title level="3" class="scroll-ani-box-title">{  renderTitle() }</Title>            { renderBoxContent() }        </div>    )}

defineComponent示意定义一个组件,也是Vue3提供的一个定义组件的办法,该办法接管一个对象作为参数,在这个对象外面有点像vue2的new Vue的参数,写vue组件的配置参数,例如props,methods等。

在这里封装了一个Title.tsx,也就是将h1 ~ h6封装成一个组件,也叫题目组件。代码如下:

import { defineComponent, PropType } from "@vue/runtime-core";export const TitleNumberCollection = [1,2,3,4,5,6];export default defineComponent({    props:{        level:{            type:[Number,String] as PropType<number|string>,            default:1,            //在这里查看level的类型            validator:(value:string | number) => {                return TitleNumberCollection.indexOf(Number(value)) > -1;            }        },        content:{            type:String as PropType<string>        }    },    setup(props,{ slots }){        const { level,content,...rest } = props;        const TitleName = "h" + level;        const renderChildren = () => slots.default ? slots.default() : props.content;        return () => (            <TitleName {...rest}>                { renderChildren() }            </TitleName>        )    }})

这个组件的实现思路就是定义一个level属性和一个content属性,前者代表应用的是h1 ~ h6之中的元素,这也是为什么TitleNumberCollection数组是[1,2,3,4,5,6]的起因。

这里为了谨严,对level做了验证,只容许传入1 ~ 6的值,也能够是字符串和数字。须要留神的就是validator是一个函数,返回的是一个布尔值,并且函数的参数必须要指定类型,否则会呈现意料之外的谬误,导致程序无奈执行。

如果组件没有写默认的插槽内容,就会应用content属性字符串作为承载的内容。应用这个组件的形式很简略,如下:

<Title level="3">这是h3元素的内容</Title><Title :level="4">这是h4元素的内容</Title>
PS: 这个组件在前面的示例中简直都有用到。

能够在onMounted钩子函数中监听页面滚动事件,如:

onMounted(() => {    triggerBottom.value = window.innerHeight * 4 / 5;    window.addEventListener("scroll",throttle(onScrollHandler,20))});

UnwrapNestedRefs类型也是Vue3定义的类型,是一个泛型,能够定义reactive办法的返回值类型,如:

interface BoxType {  active:string;  content:string;}const state:UnwrapNestedRefs<{ boxList:Array<BoxType>}> = reactive({    boxList:[]});

v-slot指令,其后跟指定的插槽名,也就是具名插槽。

less

定义Mixin实际上就是写CSS款式。如下:

.flex-center {    display: flex;    justify-content: center;    align-items: center;    flex-direction: column;}

应用形式就是把它当成函数调用,如:

//应用形式.app {    .flex-center();}

svg-gradient函数,是less的外围函数,生成一个svg渐变色,它至多有三个参数,第一个参数指定突变类型和方向,其余参数列出色彩和地位,第一个和最初一个指定色彩的地位是可选的,其余色彩必须指定地位。该函数最终会被渲染成svg图片,如下图所示:

percentage函数,承受一个浮点值作为参数,如:

percentage(.5); //渲染成50%

less当中的map对象,格局如下:

.(map名字) {    属性名: 属性值(能够是变量);}

例如:

@boxBgColor-1:#f1bd81;@boxBgColor-2:#e07e0e;.boxColors() {    lightColor:@boxBgColor-1;    darkColor:@boxBgColor-2;}

应用的时候,就像读取javascript对象那样应用中括号语法:

.test {    color:.boxColors[lightColor];}

min函数,顾名思义,求最小值,如:

min(8px,9px,10px) // => 返回8px

range函数,求范畴值,如:

range(10px, 30px, 10); // => 10px 20px 30pxpadding:range(10px, 30px, 10); // => padding: 10px 20px 30px;

fade函数,对色彩进行透明度的相加,例如:

fade(#fff,40%); // => rgba(255,255,255,.4);

相似的还有fadeout以及fadein函数。

extract函数,有2个参数,第一个参数是一个列表,第二个参数是一个索引值,也就是说该函数示意从列表当中取出列表项,如:

@textTransform:uppercase,capitalize,none,lowercase,inherit;text-transform: extract(@textTransform,1);

escape示意能够将任意的字符串转成属性或者值,格局就是~ + 字符串值,例如:

@min768: ~"(min-width: 768px)";.element {  @media @min768 {    font-size: 1.2rem;  }}

将会渲染成:

@media (min-width: 768px) {  .element {    font-size: 1.2rem;  }}

这个示例用到了很多less外围语法,对less的用法也就更深一步。

其它知识点同后面示例。

7. split panel

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

知识点同后面示例。

less

unit函数,也就是增加单位的函数,如:

unit(100,vh) // =>100vh

covert函数,转换单位,如:

covert(1s,'ms'); // => 1000ms

其它知识点同后面示例。

8. form wave

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

defineAsyncComponent函数,传入一个回调函数作为参数,回调函数的返回值必须是import('组件门路'),示意异步导入组件。如:

const AsyncFormComponent = defineAsyncComponent(() => {  return import("./components/Form.vue");});

less

pi函数,示意获取数学上的值。即3.14.....

  • ceil函数(四舍五入),
  • round函数(向上取整),
  • sqrt函数(求绝对值),
  • floor函数(向下取整),
  • length函数(获取列表的长度),
  • mod函数(求余)。

其它知识点同后面示例。

9. sound board

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

ref函数不仅能够用来定义数据,也能够用来存储一个dom元素的援用。如:

const audioRef = ref<HTMLAudioHTMLElement | null>(null);

vue template模板代码如下:

<audio ref={audioRef}></audio>

less

css选择器前缀名,能够通过定义变量,而后.@{变量名}的形式来增加css选择器前缀。如:

@prefix:sb-;.@{prefix}button-container {    //款式}// => 渲染成// .sb-button-container {//     //款式// }

sin函数,求正弦的函数。

其它知识点同后面示例。

10. dad jokes

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

Javascript

Fragment元素,也就是一个占位标签,理论不会渲染该元素,相似于vue的template元素。

window.open函数关上一个窗口,在关上之后,通过设置opener = null,能够防止window.open带来的平安问题。

如:

const win = window.open("");win && (win.opener = null);

less

color函数,用于将属性转换成色彩值字符串,如:

color(#eb6b44); // => '#eb6b44';

max函数,与min函数相同,取最大值,如:

max(600,700,800) // => 800

pow函数,幂函数,等同于javascript的Math.pow函数,传入2个参数,第一个参数为数,第二个参数为幂数。如:

pow(2,2); // => 4

:focus-visible选择器,这个是关注焦点选择器。

其它知识点同后面示例。

11. Event keyCodes

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

useCssModule办法,顾名思义,就是款式模块化,咱们能够给vue的单文件组件的style标签加上module属性,而后在setup函数当中就能够通过该办法来拜访style。例如:

<style module lang="less">.test {    //外围款式}</style><script>    //setup函数中    const style = useCssModule();</script><template>    <div :class="style.test"></div></template>

该办法还能够接一个具名参数,也就是代表获取的style模块名,比方:

<style module="name" lang="less">.test {    //外围款式}</style><script>    //setup函数中    const style = useCssModule('name');</script><template>    <div :class="style.test"></div></template>

typescript

KeyboardEvent类型,也就是键盘事件对象的类型。

less

less定义mixin(混合)与sass还是有很大的区别的,比方定义一个一般的mixin就是写一个css选择器,而后再写款式,如:

.test {    //款式代码}

而后咱们通过调用函数的形式来应用这个mixin,即:

.common {    .test();}

如果不心愿mixin被输入编译在css当中,能够给mixin退出括号,即:

.test() {    //外围款式}

应用形式依然是通过调用函数的形式,同上。

mixin同样有命名空间的概念,如:

#test(){    .test {        //这里写款式    }}

这里的#test实际上也就是命名空间,当然咱们也能够应用.test来代替#test,也是能够代表是一个命名空间名称的。

命名空间也是受爱护的,咱们能够应用when关键字,联合判断条件来让这个命名空间受爱护,如:

.mt-(@num) when (default()) {    margin-top:unit(@num,px);}

意思就是当满足默认条件的时候,咱们的.mt类名,其后跟数字前缀就会渲染出margin-top多少px的款式。例如:

.mt-(10); // => 渲染成margin-top:10px;

其它知识点同后面示例。

12. faq-collapse

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

readonly办法,能够让一个通过ref或者是reactive定义的响应式数据变成只读。如:

const state = readonly(reactive({    faqList: [        {            title:"Why shouldn't we trust atoms?",            text:"They make up everything."        },        {            title:"What do you call someone with no body and no nose?",            text:"Nobody knows."        },        {            title:"What's the object-oriented way to become wealthy?",            text:"Inheritance."        },        {            title:"How many tickles does it take to tickle an octopus?",            text:"Ten-tickles!"        },        {            title:"What is: 1 + 1?",            text:"Depends on who are you asking."        }    ]}));

此时的faqList就是只读的,无奈被批改。

less

luma函数,计算一个色彩对象的亮度。如:

luma(rgb(100, 200, 30)) // => 44%

其它知识点同后面示例。

13. random-choice-picker

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

通过withDefaults能够将defineProps包裹住,不便定义类型,并且提供props的默认值,如:

interface PropsType {    placeholder:string;}const props = withDefaults(defineProps<PropsType>(),{    placeholder:""});

计算属性的getter函数与setter函数。如:

type ListType = Array<{text?:string,isActive?:boolean}>;const computedChoices = computed<ListType>({   get(){      return choices.value;   },   set(newValue){      if(newValue !== choices.value){          choices.value = newValue;      }   }});

setTimeout提早函数的应用。

而后就是这个函数略微难以了解一些:

const changeChoices = (v:string) => v.split(choice.value.indexOf(",") > -1 ? "," : "").filter(v => v.trim()).map(v => ({ text:v,isActive:false }));

实际上也很好了解,将每个函数拆分一下,就能了解了。

其它知识点同后面示例。

14. Animated Navigation

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

知识点同后面示例。

scss

scss定义变量是$ + 变量名,而less则是@ + 变量名,scss是sass的下一版本,sass的语法有些相似于stylus,去掉了括号,然而在scss当中却保留了括号。scss中定义mixin通过@mixin。如:

@mixin common-bg {    background: linear-gradient(135deg,$bgColor-1 10%,$bgColor-2 90%);}

应用mixin就是通过@include关键字加mixin的名字。如:

.test {    @include common-bg;}

同样的scss中在选择器中应用前缀应该是#{变量名}的形式。如:

$baseSelector:an-;.#{$baseSelector}nav {    //外围款式}

scss中能够应用for循环,构造为:for 变量名 from 起始值 through 完结值。如:

@for $i from 0 through 100 {    .mt-#{$i} {        margin-top:$i + px;    }}

opacify函数,传入2个参数,第一个参数为色彩值,第二个参数为一个浮点数,示意相加的透明度,这个函数也就是为色彩值增加透明度。如:

opacify(rgba(#036, 0.7), 0.3) // => #036opacify(rgba(#6b717f, 0.5), 0.2); // rgba(107, 113, 127, 0.7)

transparentize函数,传入两个参数,同opacify函数统一,作用同opacify函数相同。如:

transparentize(rgba(#6b717f, 0.5), 0.2)  // rgba(107, 113, 127, 0.3)
opacify与transparentize函数就相似于相似于less的fadein和fadeout函数

其它知识点同后面示例。

15. incrementing-counter

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

toRefs函数,当咱们在vue中应用解构获取props时,props会失去响应式,此时咱们就须要应用toRefs将props包裹一下,让props不失去响应式,这在Counter.vue文件当中是正文了的。

scss

知识点后面示例讲过。

其它知识点同后面示例。

16. Drink Water

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

javascript没什么好说的,倒是typescript有2个类型须要解释一下。

StyleValue类型,顾名思义,就是款式值的类型,是typescript内置类型。

keyof关键字,前面跟一个类型,示意一个类型属于前面类型的一个子类型。如:

interface DataType {    name: string;    age: number;}const a: keyof DataType = 1;

scss

继承的语法,首先写一个公共的款式,而后通过@extend关键字应用,并且能够写多个继承,通过,分隔。如:

.test-1 {    //外围款式}.test-2 {    //外围款式}.common {    @extend .test-1,.test-2;}

其它知识点同后面示例。

17. Movie App

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

javascript也没有什么新知识点,次要是typescript新增了3个类型,FocusEvent,HTMLInputElement和Partial类型

FocusEvent就是关注焦点事件对象类型,HTMLInputElement为input元素的类型,Partial为typescript内置类型,将所有类型变成可选的,也是一个泛型。

scss

percentage函数,原理同less的percentage没什么好说的。

mixin同样也能够传参数,并且在@include的时候传入即可。

相似border这样的,还能够写成嵌套语法。如:

border: {    width:1px;    style:solid;    color:ffefefe;}// => 渲染border-width: 1px;border-style:solid;border-color:#fefefe;

其它知识点同后面示例。

18. background slider

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

nextTick函数,传入一个回调函数作为参数,该函数为期待下一次 DOM 更新刷新的工具办法,返回值是一个promise。如示例:

<script setup>import { ref, nextTick } from 'vue'const count = ref(0)async function increment() {  count.value++  // DOM 还未更新  console.log(document.getElementById('counter').textContent) // 0  await nextTick()  // DOM 此时曾经更新  console.log(document.getElementById('counter').textContent) // 1}</script><template>  <button id="counter" @click="increment">{{ count }}</button></template>

scss

clamp函数,传入3个参数,返回第二个参数的值,第一个参数为最小值,第3个参数为最大值。语法:

clamp($min,$number,$max) // => $number

三个参数都必须有单位或者无单位,如果$number小于$min的值,则返回$min,如果$number大于$max的值,则返回$max。

map-get函数,获取map类型的值,来看一个示例:

$font-weights: ("regular": 400, "medium": 500, "bold": 700);map-get($font-weights, "medium"); // 500map-get($font-weights, "extra-bold"); // null

其它知识点同后面示例。

19. theme clock

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

知识点同后面示例。

可选链操作符?的应用。

typescript

Readonly类型,示意数据类型只读。

CSSProperties类型,就是css属性名的类型。

scss

@if...@else...判断语句。@function定义函数,@return 返回函数值。如:

@function setMargin($i,$j,$unit){    $result:0;    @for $_ from $i through $j {      @if $unit {        $result:$_ + $unit;      } @else {        $result:$_;      }    }    @return $result;}

这个函数示意设置间距,传入开始值,完结值以及单位。

max函数,同less的max函数一样。如:

$maxWidth:250px,300px,350px;max-width: max($maxWidth...); // => 350px

其它知识点同后面示例。

20. button-ripple-effect

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

没什么知识点好说的,有个MouseEvent示意鼠标事件对象的类型,以及HTMLButtonElement示意button元素的类型。

scss

能够在scss当中引入命名空间,而后应用sass内置的函数。如:

@use "sass:math";//能够应用math函数//如math.atan2,math.pow

其它知识点同后面示例。

21. drawing-app

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

动静组件,component,传入一个is关键字,is关键字作为组件名。如:

<component is="div" ref="container"></component> // => 渲染一个div元素

本示例中封装了一个基于我的js实现的色彩选择器色彩选择器组件,代码如下:

<script setup lang="ts">    import { nextTick, onMounted, PropType } from '@vue/runtime-core';    import { ref } from '@vue/reactivity';    import ewColorPicker from 'ew-color-picker';    import "ew-color-picker/dist/ew-color-picker.min.css";    const props = defineProps({        name:{            type:String as PropType<string>,            default:"div"        },        option:{            type:Object as PropType<object>,            default:() => ({})        }    });    const container = ref(null);    onMounted(() => {        nextTick(() => {            new ewColorPicker({ el:container.value,...props.option }) as any;        })    })</script><template>    <component :is="props.name" ref="container"></component></template>

自定义组件v-model指令的实现,首先是定义一个叫modelValue的props,接着在组件外部提交自定义事件emit('update:modelValue')即可,当然也能够批改名字,不过应用形式就要相似:v-model:[属性名]。例如:

const props = defineProps({    modelValue:[String,Number] as PropType<string | number>});const emit = defineEmits(["update:modelValue"]);//模板元素// <input @input="onInputHandler" :value="props.modelValue" />

scss

list.nth能够获取列表中对应渲染的值,传入2个参数,第一个是列表,第二个则是列表索引值。如:

//导入list命名空间@use "sass:list";//定义列表$display:block,flex,inline-block,inline,inline-flex,none;.el-block {    display: list.nth($display,1); //=> 渲染block}

以上代码定义一个类名为el-block,渲染display:block的款式。

其它知识点同后面示例。

22. drag-n-drop

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

拖拽事件的应用。

scss

@each...in循环,同@for循环相似,如:

$font-weight:normal,lighter,bold,bolder,100,200,300,400,500,600,700,800,900;@each $value in $font-weight {    .fw-#{$value} {        font-weight: $value;    }}

以下这个函数也有点意思:

@use "sass:string";/** 截取属性字符*/@function propSlice($prop, $start, $end) {    @return string.unquote(string.slice(string.quote($prop), $start, $end));}

其它知识点同后面示例。

23. content-placeholder

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例展现了如何封装一个骨架屏卡片组件,其中波及到的知识点后面总结过,所以这里不再总结。

24. kinetic-loader

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

25. sticky-navbar

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

一个SVG Icon组件的写法:

<template>    <svg         viewBox="0 0 1024 1024"         version="1.1"         xmlns="http://www.w3.org/2000/svg"         :width="width"        :height="height"    >        <template v-if="Array.isArray(iconComponent)">            <path                 v-for="(item,index) in iconComponent"                 :key="item.prop + index"                 :fill="item.color ? item.color : color"                 :d="item.prop"            ></path>        </template>        <template v-else-if="isString(iconComponent)">             <path :fill="color" :d="iconComponent"></path>        </template>    </svg></template><script lang="ts" setup>    import { iconPathData } from "@/utils/iconPathData";    import type { IconType } from "@/utils/iconPathData";    import { isString } from "@/utils/utils";    import { computed } from "vue";    const props = defineProps({        width:{            type:Number,            default:30        },        height:{            type:Number,            default:30        },        type:String,        color:{            type:String,            default:"#fff"        }    });    const iconComponent = computed(() => iconPathData[props.type as keyof IconType]);</script>

仿佛这样封装不太好。

transition组件,用于增加过渡成果的组件。

Promise.allSettled这个能够参考文档。

其它知识点同后面示例。

26. double-slider

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

27. toast-notification

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

typescript

这个函数有点意思:

interface ConsoleType {    black: string;    red: string;    green: string;    yellow: string;    blue: string;    magenta: string;    cyan: string;    white: string;    bgBlack:string;    bgRed: string;    bgGreen:string;    bgYellow:string;    bgBlue: string;    bgMagenta:string;    bgCyan: string;    bgWhite:string;}export function colorize<T>(...args:Array<T>){    return {        black: `\x1b[30m${args.join(' ')}`,        red: `\x1b[31m${args.join(' ')}`,        green: `\x1b[32m${args.join(' ')}`,        yellow: `\x1b[33m${args.join(' ')}`,        blue: `\x1b[34m${args.join(' ')}`,        magenta: `\x1b[35m${args.join(' ')}`,        cyan: `\x1b[36m${args.join(' ')}`,        white: `\x1b[37m${args.join(' ')}`,        bgBlack: `\x1b[40m${args.join(' ')}\x1b[0m`,        bgRed: `\x1b[41m${args.join(' ')}\x1b[0m`,        bgGreen: `\x1b[42m${args.join(' ')}\x1b[0m`,        bgYellow: `\x1b[43m${args.join(' ')}\x1b[0m`,        bgBlue: `\x1b[44m${args.join(' ')}\x1b[0m`,        bgMagenta: `\x1b[45m${args.join(' ')}\x1b[0m`,        bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`,        bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m`    };}

能够参考这里具体理解这个函数。

接口的继承,如:

export function consoleByColorKey<T,U extends keyof ConsoleType>(str:string,key="black"){    return console.log(colorize(str)[key as U]);}

createVNode办法,vue外部办法,提供一个创立vNode节点的办法,这也是这个示例的难点,而后是render函数。

其它知识点同后面示例。

28. github-profiles

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

29. double-click-heart

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

30. auto-text-effect

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

31. password generator

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

获取自定义属性

const target = e.target as HTMLDivElement;const lang = target.dataset.lang;

实现复制文本的办法:

const confirm = () => {    (window as any).ewConfirm({        title:data.value.confirmTitle,        content:data.value.confirmContent,        showCancel:false    })}// `navigator.clipboard.writeText` not working in wechat browser.if(navigator.userAgent.toLowerCase().indexOf('micromessenger') === -1){  navigator.clipboard.writeText(password.value).then(() => confirm())}else{    const input = document.createElement("input");    input.value = password.value;    document.body.appendChild(input);    input.select();    document.execCommand("copy");    input.remove();    confirm();}

这里用了两个插件。

其它知识点同后面示例。

32. good-cheap-fast

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

33. Notes App

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

classnames函数的实现,源码值得细细品读:

export type Value = boolean | string | number | undefined | null | Symbol;export type Mapping = Record<string,unknown>;export interface ArgumentArray extends Array<Argument> {}export type Argument = Mapping | Mapping | ArgumentArray;const hasOwn = Object.prototype.hasOwnProperty;export default function classnames(...args:ArgumentArray):string{    const classes = [];    for(let i = 0,len = args.length;i < len;i++){        const arg = args[i];        if(!arg){            continue;        }        if(typeof arg === "string" || typeof arg === "number"){            classes.push(arg);        }else if(Array.isArray(arg)){            if(arg.length){                const __class = classnames.apply(null,arg);                if(__class){                    classes.push(__class)                }            }        }else if(typeof arg === "object"){            if(arg.toString === Object.prototype.toString){                for(let key in arg){                    if(hasOwn.call(arg,key) && arg[key]){                        classes.push(key);                    }                }            }else{                classes.push(String(arg));            }        }    }    return classes.join(" ");}

而后就是这3个工具函数,如下:

export function createUUID(){    return Math.floor(Math.random() * 10000) + '-' + Date.now().toString().slice(0, 4) + '-' + Math.floor(Math.random() * 10000);}export function getNotesData(key:string = "notes"){    try {        return JSON.parse(localStorage.getItem(key) as string);    } catch (error) {        return [];    }}export function setNotesData(key:string,value:Array<any>){    return localStorage.setItem(key,JSON.stringify(value));}

创立一个uuid以及存储笔记数据的会话存储办法的一个封装。

其它知识点同后面示例。

34. animated-countdown

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

javascript

defineExpose办法,用于向父组件传递办法,能够容许父组件通过ref来拜访子组件的办法。如:

defineExpose({    startRunAnimation});const startRunAnimation = () => {    //...}

InstanceType类型为typescript内置的一个类型,如下:

InstanceType<typeof AsyncNumberGroup> | null> // => 代表返回这个组件AsyncNumberGroup的实例类型

其它知识点同后面示例。

35. image-carousel

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例展现了一个轮播组件的封装,但这个示例仿佛还有点小bug,源码波及到的知识点在后面的示例当中也可能找到,不用赘述。

36. hover board

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

37. pokedex

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

创立一个index.d.ts,能够定义命名空间,而后定义接口返回的类型,如下:

declare namespace 命名空间名 {    //定义接口}

这样做的益处就是我能够间接在组件当中定义该类型,vsCode会主动帮咱们显示拜访的属性,而后咱们就不必要去打印数据看看数据结构再来决定获得什么属性了,这在理论开发当中是一个很罕用的晋升开发效率的技巧,这也是为什么typescript在后续保护当中十分好保护的起因之一。

其它知识点同后面示例。

38. mobile-tab-navigation

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

39. password-strength-background

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例次要展现了如何将tailwindcss增加到vue我的项目当中去,跟着官网提供的教程就能够了。

知识点同后面示例。

40. 3d-background-boxes

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

41. verify-account-ui

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

42. live-user-filter

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这里有个预加载组件和加载组件值得钻研一下,预加载组件的实现思路就是利用Image构造函数来提前加载图片,如果图片未申请实现,则显示loader组件。对于loader组件的实现能够参看源码。

watchEffect函数,与watch函数有所不同,该函数是一个副作用函数,能够间接传入一个回调函数,外部会主动监听数据的变动,当数据扭转后,该函数外部就会执行。

其它知识点同后面示例。

43. feedback-ui-design

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例值得学习的是应用css做了一个翻转成果,其实也就是利用了rotate函数。

其它知识点同后面示例。

44. custom-range-slider

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

45. netflix-mobile-navigation

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例展现了一个递归组件的实现,其实参考官网示例代码就能够学习到思路。

其它知识点同后面示例。

46. quiz-app

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

47. testimonial-box-switcher

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

知识点同后面示例。

48. random-image-feed

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这个示例预览组件的实现还是值得学习的,如下:

<template>    <Teleport to="body">        <div class="preview-mask" :class="{ show: modelValue }" @click="emit('update:modelValue', false)">            <async-pre-load-image :src="src" class="preview-mask-image"></async-pre-load-image>        </div>    </Teleport></template><script lang="ts" setup>import { defineAsyncComponent, PropType, toRefs } from 'vue';const AsyncPreLoadImage = defineAsyncComponent(() => import('./PreLoadImage.vue'));const props = defineProps({    src: String as PropType<string>,    modelValue: Boolean as PropType<boolean>});const emit = defineEmits(['update:modelValue']);const { src, modelValue } = toRefs(props);emit('update:modelValue');</script>

波及到了Teleport组件的应用。

其它知识点同后面示例。

49. todo-list

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

本示例实现了一个Modal弹框组件,并且实现了一个自定义clickoutside指令。

其它知识点同后面示例。

50. insect-catch-game

成果如图所示:

  • 源码
  • 在线示例
学到了什么?

这是一个比拟综合的示例了,简直涵盖了后面所有示例的语法,自己集体也感觉这个示例值得学习,细细品味一番。

看完本文,你对vue3以及scss和less是否有了更深刻的理解呢?当然兴许还有我没有总结到的知识点,更粗疏的就要去通读源码了,我集体是认为每一个示例都波及到了相应的知识点,至多亲手实现了这50个示例,我对vue3的应用更加纯熟了。

如果感觉本文有任何谬误,欢送批评指正。