Ts10-利用自建组件库框架写组件03

83 阅读1分钟

checkbox

// 复杂组件类型都定义类型。
// lerna create checkbox
// lib rename to src

src
    checkbox.vue
        <template>
            <div>
                <div>
                    <input type="checkbox" />
                </div>
                
                <div>
                    <slot></slot>
                </div>
                
            </div>
        
        </template>
                
        <script lang="ts>
            import {definedComponent} from "vue";
            export default definedComponent({
                name: "ZCheckbox",
                setup(props, ctx){

                }
            })
        </script>
        
   CheckboxGroup.vue
       <template>
            <div>
                checkbox
            </div>
        </template>
        <script lang="ts>

        import {definedComponent} from "vue";
        export default definedComponent({
            name: "ZCheckboxGroup",
            props: {
                name:{
                    type:String,

                },
                inder: {
                    type:Boolaan, 
                },
                checked: {
                    type:Boolean
                },
                disabled:{
                    type: Boolean,
                },   
                label: [String,Number,Bolean],
                modelValue: [String,Number,Boolean]
            },
            setup(props, ctx){

            }
        })
        </script>
// index.ts
// 注册到全局组件  
yarn install // 把这两个组件装到全局

// checkbox 属性定义 定义写类型。
// 创建 checkbox-types.ts
export interface CheckboxProps{
    inder?:boolean,
    checked?:boolean,
    name?:string,
    disabled?:boolean,
    label?:string|number|boolean,
    modelValue?:string|number|boolean, // vue会把 v-model 编译成modelValue 事件叫 update:modelValue
}

let V = reactive([])
// V是个响应式的
// 数组里面[]这里面是响应式的
// V = [] 这样改完了相当于把地址空间改成了非响应式的。
// v-model="V" 不能用这个就变成非样式的了
let V = reactive({
    list: null
})
// v-model="V.list"是可以的
// 为了绑定v-model的值尽量用 ref 绑定
// 因为这个用了.value 相当于.list的变种
// Vue3 modelValue
<input v-model="model" :checked="isChecked" />
setup(props,ctx){
    const {emit} = getCurrentInstance();
    const model = computed({
        get(){
            return props.modelValue
        },
        set(val){
            emit("update:modelValue", val)
        }
    })

    const isChecked = computed(()=>{
        return props.modelValue;
    })
    return {
        model,
        isChecked
    }
},
emits: ['update:modelValue'] // 这个是在子组件声明的否则就绑定在父组件了。

// 模版解析会把 v-model 解析成 modelValue 和 update:modelValue 
// checked 和 value不是一个东西 checked 是 input的一个状态

// 事件
emits:['change'],
setup(props,ctx){
    const handlerChange = (e:InputElement) => {
        const target = e.target as HTMLInputElement
        const changeVal = target.checked:true:false
        ctx.emit("change", changeVal)
    }
    
}


checkbox-group

CheckboxGroup.vue
<template>
    <div class="z-checkbox-group">
        <slot></slot>
    </div>
</template>
<script lang="ts>
// 这里的v-model绑定一定不要reactive否则不生效 数组 因为直接改地址了用ref
import {definedComponent} from "vue";
export default definedComponent({
    name: "ZCheckboxGroup",
    props: {
        modelValue: Array // 父组件传递给子组件传递给modelValue
    },
    emits: ['change',"update:modelValue"],
    setup(props, ctx){
        const cpd:ComputedRef = computed({
            get(){
                return props.modelValue
            }
        })
        // 儿子修改了通知父亲
        const changeEvent = (val) => { // 子节点调用这个进行更新 
            const INS = getInstance();
            INS.emit("change", val);
            INS.emit("update:modelValue", val);
        }

        provide('ZCheckboxGroup', {
            name: 'ZCheckboxGroup', // 为了让子节点知道是有父节点的 因为这个玩意可以单独的出来。
            cpd,
            changeEvent
        });
    }
})
</script>


// 子组件的改造。 ZCheckbox
checkbox.vue
<template>
    <div>
        <div>
            <input type="checkbox" />
        </div>
        <div>
            <slot></slot>
        </div>
        checkbox
    </div>
</template>
<script lang="ts>
import {definedComponent} from "vue";
export default definedComponent({
    name: "ZCheckbox",
    setup(props, ctx){

        // 儿子要把provide的数据拿过来用
        // 如果用了checkbox-group现在没有modelValue了
        // inject
        const IJ = inject<any>('ZCheckboxGroup', {}); // 这里可以传入一个泛型
        
        if(IJ.name){ // 如果是带着checkbox-group嵌套使用的
            const model = computed({
                get(){
                    return IJ.modelValue?.value || props.modelValue // type="checkbox" v-model="可以用数组"
                },
                set(val){
                    

                    // 只要值发生了改变就走这这里来调用父亲的更新。
                    if(IJ.name) {
                        return IJ.changeEvent?.(val); // val是个数组v-model绑定个数组更新给的也是个数组,注意最新的类型一定是数组。
                    } else {
                        emit("update:modelValue", val);
                    }
                }
            })

        }


        // 现在modelValue是个数组 如何做是否选中? 
        // 如果是group的现在用的是父亲的modelValue: Array
        // 需要借助于label唯一属性
        if(IJ.name && Array.isArray(model.value)){ // 针对父组件传过来的是数组。
            // 可以去拿一下label属性
            if(model.value.includes(props.label)){
                // 需要选中的
            } else {
                // model.value 默认就是true false
            }

            // 给<input type="checkbox" :value="label" /> 给他来一个value  这个玩意有点屌屌的,如果 v-mode="是一个数组" :value="值" 如果数组包含了这个值就是选中的。

            // <slot>{{label}}</slot>
        }

        // 子组件点击时候需要调用父亲组件的方法 changeEvent  这里发射的也是个数组。
        // 每次的状态发生了改变需要通知父亲

    }
})
</script>


// 计算属性的类型是ComputedRef

// <input 如果v-model="这里面的这个玩意是个数组" 需要带着:value="值" /> 这么来玩 vue的特点。对于checkbox而言 vue3 v-model 和 value 不冲突了。 vue2只要前面那个行了。VUE3需要多个:value