uniapp中videojs、renderjs的使用-程序员宅基地

技术标签: uniapp  # uniapp  javascript  

在uniapp中使用了某些前端库或iframe,需要操作这些库中的dom的时候, 而uni上又没有document等基础对象。也就无法操作这些dom去实现一些交互逻辑,那么,涉及到这些的前端类库就无法使用,例如html2、canvas、image、video。而要用这些怎么办,这是用就出现了renderjs这种视图层工具来进行渲染。大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力

使用方法:

  1. 在原有script下方再添加script,其中lang="renderjs"固定, module=“demo”,module的名字任意起
  2. 可以通过 this.$ownerInstance 获取当前组件的 ComponentDescriptor 实例。类似于vm
  3. 视图层绑定事件通过 module名称 . 逻辑层定义方法,有两个参数,1.事件对象event,2. 当前组件实例ComponentDescriptor
  4. 两个script间的通信需要通过:this.$ownerInstance 全局组件实例 或者 事件参数ComponentDescriptor 身上的callMethod方法,去抛出方法、传值,类似于vue组件间emit
  5. 可以使用 vue 组件的生命周期不可以使用 App、Page 的生命周期

使用参考:https://blog.csdn.net/dabaooooq/article/details/129272111

代码

uniapp在APP端video层级最高,不能被其它覆盖,引入videojs实现,使用renderjs实现原生的DOM操作。

<template>
    <div class="full_screen_video" v-show="visible" :class="{ 'normal': !fullScreen }">
        <!-- 遮盖video 添加点击事件 -->
        <div class="video_mask"  @click="foldShortVideo" ></div>
        <p v-if="fullScreen" class="back" @click="closeDialogHandle">
            <image src="@i/common/back_white.svg" alt=""></image>
            <span>{
    {
     title}}</span>
        </p>
        <view 
            :info="videoItem" 
            :change:info="videos.updateVideo" 
            :options="videoOptions" 
            :change:options="videos.optionsChange"
            class="video_box"
            ref="videoEle" 
            id="videoEle">
        </view>
        <view class="video_control_box" v-if="fullScreen" >
            <!-- 开始结束时间 -->
            <view class="video_time">
                <span>{
    {
     formatTime(videoCurrentTime) }} </span> <span>{
    {
     formatTime(videoTotalTime) }}</span>
            </view>
            <!-- 视频播放器 -->
            <div class="video_control">
                <p class="disp_ac">
                    <image  v-if="!isStart" src="@i/video/icon_video_start.svg" mode="widthFix" @tap="startAndStop('start')" alt=""></image>
                    <image v-else src="@i/video/icon_video_stop.svg" mode="widthFix" @tap="startAndStop('stop')" alt=""></image>
                    <image  src="@i/video/icon_video_next.svg" mode="widthFix" @tap="playNext" alt="" v-if="videoList.length > 0"></image>
                </p>
                <p>
                    <view :class="{'normal_mode':normalMode}"  class="formation_select_box mr60" @click="showOption = !showOption">
                        <span class="select_text">{
    {
     speedValue +'x'}}</span>
                        <view class="select_menu" :class="{ ani: showOption }" v-show="showOption">
                            <view class="select_menu_item" v-for="item in speedOptions" :key="item.value">
                                <span :class="{'active': speedValue === item.value}" @click="changeSpeed(item.value)">{
    {
     item.label +'x'}}</span>
                            </view>
                        </view>
                    </view>
                    <image v-if="normalMode" src="@i/video/full_screen.svg" mode="widthFix" @tap="fullScreenVideo" alt=""></image>
                </p>
            </div>
        </view>
        <view v-else class="video_control_box video_control_box_small" >
            <div class="time_bar_box">
                <div class="time_btn">
                    <image  v-if="!isStart" src="@i/video/icon_video_start.svg" mode="widthFix" @tap="startAndStop('start')" alt=""></image>
                    <image v-else src="@i/video/icon_video_stop.svg" mode="widthFix" @tap="startAndStop('stop')" alt=""></image>
                    <image  src="@i/video/icon_video_next.svg" mode="widthFix" @tap="playNext" alt="" v-if="videoList.length > 0"></image>
                </div>
                <div class="time_bar">
                    <span>{
    {
     formatTime(videoCurrentTime) }} </span> <span>{
    {
     formatTime(videoTotalTime) }}</span>
                </div>
            </div>
            <div class="video_btn">
                <view  class="formation_select_box mr50" @click="showOption = !showOption">
                    <span class="select_text">{
    {
     speedValue +'x'}}</span>
                    <view class="select_menu" :class="{ ani: showOption }" v-show="showOption">
                        <view class="select_menu_item" v-for="item in speedOptions" :key="item.value">
                            <span :class="{'active': speedValue === item.value}" @click="changeSpeed(item.value)">{
    {
     item.label +'x'}}</span>
                        </view>
                    </view>
                </view> 
                <image src="@i/video/download.svg" mode="widthFix" @tap="downloadVideo" alt=""></image>
                <image v-if="normalMode" src="@i/video/full_screen.png" mode="widthFix" @tap="fullScreenVideo" alt=""></image>
            </div>
        </view>
        <!-- 视频列表 -->
        <div class="video_list" v-if="showVideoList && videoList.length" >
             <scroll-view scroll-x="true" >
                <div class="video_list_item">
                    <div v-for="(item, index) in videoList" :key="index" class="video_item" :class="{'active': index === currentVideoIndex}" @click="playVideo(item, index)">
                        <div class="video_img">
                            <image class="snapshot" :src="item.snapshot && !item.imgError ? item.snapshot : defaultSnapshot" @error="item.imgError = true" alt="snapshot" ></image>
                            <span class="total_time" v-if="item.end && item.start">
                                {
    {
    formatTime(item.end - item.start)}}
                            </span>
                        </div>
                        <div class="clip_info">
                            <div class="text_over">{
    {
    item.name || item.label  || ''}}</div>
                            <div class="video_list_time">{
    {
     formatDate(item.createTime).split('-').slice(0,3).join('/').split(' ').slice(0,1).join() }}</div>
                        </div>
                    </div>
                </div>
            </scroll-view>
        </div>
    </div>
</template>

<script>
export default {
    
    name: 'pad-video-play',  // 在主视频内播放的组件,短片会跳转到主视频对应的时间
    props: {
    
        // 控制显示隐藏
        visible: {
    
            type: Boolean,
            default: false
        },
        // 主视频下的短视频播放列表
        videoList: {
    
            type: Array,
            default:() => []
        },
        // 主视频播放源
        videoMain: {
    
            type: Object,
             default: () => {
     }
        },
        // 视频类型, 默认为全屏播放
        videoType: {
    
            type: String,
            default: 'full_screen'
        },
    },
    data() {
    
        return {
    
            videoCurrentTime: 0, // 视频当前时间
            videoTotalTime: 0,   // 视频总时长
            isStart: false,      // 是否开始
            volumeValue: 1,     // 音量初始值(0-1)
            showVideoList: true,    // 是否显示视频列表
            currentVideoIndex: -1,   // 当前播放的视频下标
            defaultSnapshot: require("static/images/video/default_snapshot.svg"), // 默认缩略图
            videoOptions: {
    
                closeDialog: false
            },   // 视频操作选项
            fullScreen:  this.videoType === 'full_screen',    // 是否是全屏
            speedValue: '1.0',     // 初始播放速度
            showOption:false, // 控制倍速弹窗
            speedOptions: [     // 阵型选项
                {
     label: '2.0', labelEn: '2.0', value: '2.0' },
                {
     label: '1.5', labelEn: '1.5', value: '1.5' },
                {
     label: '1.25', labelEn: '1.25', value: '1.25' },
                {
     label: '1.0', labelEn: '1.0', value: '1.0' },
                {
     label: '0.5', labelEn: '0.5', value: '0.5' },
            ],
            videoItem: {
    },
            title:''
        };
    },
    computed: {
    
        // 是否是正常模式下的视频播放
        normalMode() {
    
            let boolean = this.videoType === 'normal';
            return boolean;
        }
    },
    watch: {
    
        currentVideoIndex(newVal) {
    
            this.$emit('change-video-index', newVal);
        },
        videoMain: {
    
            handler (newVal) {
     
                this.videoItem = {
    
                    url: newVal.url
                }
                this.title = newVal.name 
            },
            immediate: true,
            deep:true
        },
        visible(newVal) {
    
            if (newVal) {
     
                 this.videoOptions = {
    
                    closeDialog: false,
                    volumeChangeOption: {
     volume: 1 } 
                }
                this.volumeValue = 1;
            }
        }
    },

    methods: {
    
        foldShortVideo(){
    
            this.showVideoList = !this.showVideoList
        },
        // 关闭弹框
        closeDialogHandle () {
    
            this.videoOptions = {
    
                closeDialog: true
            }
            if (this.videoType === 'full_screen') {
    
                // setTimeout(() => { 
                    this.$emit('cancelVideo', false);
                // },100)
            } else {
    
                this.fullScreen = false;
            }
            this.showVideoList = false;
            this.$emit('update:visible',false)
        },
        // 开始视频
        onPlayerPlay() {
    
            this.speedValue = '1.0'
            this.isStart = true;
        },
        // 实时更新
        onTimeUpdate(currentTime){
    
            this.videoCurrentTime = currentTime;
        },
        // 暂停视频
        onPlayerPause() {
    
            this.isStart = false;
        },
        // 加载视频源数据
        onLoadedmetadata(totalTime) {
    
            this.videoTotalTime = totalTime;
        },
        // 开始或暂停视频
        startAndStop(type) {
    
            this.videoOptions = {
    
                startAndStopOption: {
     type }
            }
        },
        // 改变视频音量
        volumeChange(volume) {
    
            this.volumeValue = volume;
            this.videoOptions = {
    
                volumeChangeOption: {
     volume } 
            }
        },
        // 播放视频
        playVideo(item, index) {
    
            this.speedValue = '1.0'
            // // 在正常模式播放下, 不可重复点击当前视频
            if (this.normalMode && item && this.currentVideoIndex === index) {
    
                return;
            }
            this.$set(this.videoItem, 'startTime', item.start);
            this.currentVideoIndex = index;
            this.videoList.forEach(item => {
    
                item.forceUpdate = false
            })
            item.forceUpdate = true
            
        },
        // 改变视频的速度
        changeSpeed(speed) {
    
            this.speedValue = speed || '1.0';
            this.videoOptions = {
    
                playbackRate: {
     speed }
            }
        },
        // 播放下一个
        playNext(){
    
            this.speedValue = '1.0'
            this.videoList.forEach(item => {
    
                item.forceUpdate = false
            })
            let index = this.currentVideoIndex;
            
            if(this.currentVideoIndex+1<this.videoList.length){
     
                this.currentVideoIndex = index+1;
                this.$set(this.videoList[index+1],'forceUpdate',true)
                this.$set(this.videoList, index + 1, this.videoList[index + 1]);
                this.$set(this.videoItem, 'startTime', this.videoList[index+1].start);
            }else{
     
                this.currentVideoIndex = 0;
                this.$set(this.videoList[0],'forceUpdate',true)
                this.$set(this.videoList, 0, this.videoList[0]);
                this.$set(this.videoItem, 'startTime', this.videoList[0].start);
            }
        
        },
        // 进入/退出 全屏视频
        fullScreenVideo() {
    
            this.fullScreen = !this.fullScreen;
        },
        // 格式化时间
        formatTime(result) {
    
            let h =  Math.floor(result / 3600) < 10 ? "0" + Math.floor(result / 3600) : Math.floor(result / 3600);
            let m = Math.floor((result / 60) % 60) < 10 ? "0" + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60);
            let s = Math.floor(result % 60) < 10 ? "0" + Math.floor(result % 60) : Math.floor(result % 60);
            return Math.floor(result / 3600) == 0 ? m + ":" + s : h + ":" + m + ":" + s;
        },
        // 格式化日期
        formatDate(createTime){
    
            let date = new Date(createTime);
            let str = `${
      date.getFullYear()}-${
      date.getMonth() + 1}-${
      date.getDate()} ${
      date.getHours()}:${
      date.getMinutes()}:${
      date.getSeconds()}`;
            return str;
        }
    }
};
</script>

<script module="videos" lang="renderjs">
    import './video-offset.js';         // videojs 引入
    import Videojs from 'video.js';
    import 'video.js/dist/video-js.css';
    export default {
    
        data() {
    
            return {
    
                videoPlayer: null, // 当前视频播放器
            }
        },
        mounted() {
    
           
        },
        methods: {
    
          
            // 初始化视频
            initVideoJS(item) {
    
              	if(this.videoPlayer){
    
					this.videoPlayer.dispose();
					this.videoPlayer = null;
				}
                let that = this;
                let videoEle = document.createElement('video');
                videoEle.style = 'width:100%; height:100%';
                videoEle.setAttribute("class", "video-js vjs-big-play-centered");
                let videos = document.getElementById('videoEle');
                console.log(videos);
                videos.appendChild(videoEle)
       
                let option = {
    
                    controls: true,     // 是否显示控制条
                    preload: 'auto',    // 是否预加载视频数据
                    muted: false,       // 是否静音
                    language: 'zh-CN',  // 设置语言
                    autoplay: true,    // 自动播放, 正常模式下不进行自动播放
                    sources: [  // 视频源
                        {
    
                            type: "video/mp4",
                            src: item.url
                        }, {
    
                            type: "video/webm",// webm格式
                            src: item.url
                        }, {
    
                            type: "video/mov", // mov格式
                            src: item.url
                        },
                    ],
                    controlBar: {
           // 设置控制条组件
                        children: [
                            {
     name: 'progressControl' },     // 播放进度条
                        //     // { name: 'fullscreenToggle' }     // 全屏按钮
                        ]
                    }
                };
                // video.js初始化实例化的对象
                this.videoPlayer = Videojs(videoEle, option, function onPlayerReady() {
    
                    // 开始视频
                    this.on('play', function() {
    
                        that.$ownerInstance.callMethod('onPlayerPlay');
                    })
                    // 暂停视频
                    this.on('pause', function() {
    
                        that.$ownerInstance.callMethod('onPlayerPause');
                    })
                    // 实时更新
                    this.on('timeupdate', function() {
    
                        let currentTime = that.videoPlayer ? that.videoPlayer.currentTime() : 0;
                        that.$ownerInstance.callMethod('onTimeUpdate', currentTime);
                    })
                    // 加载视频源数据
                    this.on('loadedmetadata', function() {
    
                        let totalTime = parseInt(that.videoPlayer.duration()) || 0;
                        that.$ownerInstance.callMethod('onLoadedmetadata', totalTime);
                    })
                });
            },
            // 监听 videoData 数据变更
            updateVideo(newValue) {
    
                if(!newValue || !newValue.url) return;
                if(this.videoPlayer && newValue.startTime){
    
                    this.videoPlayer.currentTime(newValue.startTime)
                    return
				}
                this.initVideoJS(newValue);
            },
            // 监听改变视频操作选项
            optionsChange(newValue) {
    
                if (newValue && newValue.startAndStopOption) {
    
                    // 开始或暂停视频
                    let {
     type } = newValue.startAndStopOption;
                    type === 'start' ? this.videoPlayer.play() : this.videoPlayer.pause();
                } else if (newValue && newValue.volumeChangeOption) {
    
                    // 改变视频音量
                    let  {
     volume }  = newValue.volumeChangeOption;
                    this.videoPlayer && this.videoPlayer.volume(volume);
                } else if (newValue && newValue.closeDialog) {
    
                    console.log('销毁了')
                    // 销毁videoJs实例
                    this.videoPlayer && this.videoPlayer.dispose();
                    this.videoPlayer = null
                } else if (newValue && newValue.continuePlay) {
    
                    // 继续播放视频
                    let {
     url } = newValue.continuePlay;
                    this.initVideoJS(url);
                } else if(newValue &&  newValue.playbackRate){
    
                    let {
     speed } = newValue.playbackRate;
                    // 改变视频的播放速度
                    this.videoPlayer && this.videoPlayer.playbackRate(speed);
                }
            }
        }
    }
</script>

<style lang='less' scoped>
.video_mask {
    
    position: absolute;
    width: 100%;
    height: calc(100% - 62.81rpx);
    top: 0;
    left: 0;
    background-color: transparent;
    z-index: 1;
}
::v-deep {
    
    // 视频style
    .video_box{
    
        width: 100%;
        height: 100%;
        video{
    
            object-fit:fill;
        }
    }
    .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar{
    
        opacity: 1;
    }
    .video-js{
    
        position: relative;
        .vjs-control-bar {
    
            width:663.32rpx;
            left: 43.34rpx;
            bottom: 47.9rpx;
            background-color: transparent;
            z-index: 105;
            opacity: 1;
        }
        .vjs-play-progress{
    
            background: #38CB89;
            &::before{
    
                color: #38CB89;
            }
        }
        .vjs-slider{
    
            background-color: rgba(255, 255, 255, 0.36);
        }
    }
}
.disp_ac{
    
    display: flex;
    align-items: center;
}
/* 文字超出部分设置为... */
.text_over {
    
    max-width: 85%;
    word-break: break-all;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2; /* 这里是超出几行省略 */
    overflow: hidden;
}
.full_screen_video{
    
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 102;
    left: 0;
    top: 0;
    box-sizing: border-box;
    color: #fff;
    font-family: 'SysFontR';
    // 默认视频样式
    &.normal{
    
        width: 100%;
        height: 100%;
        position: relative;
        .video_list,.video_shrink{
    
            display: none;
        }
        .video_control_box{
    
            width: 100%;
            height: 37.69rpx;
            position: absolute;
            left: 0;
            bottom: 4.71rpx;
            z-index: 5;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 0 10.05rpx;
            box-sizing: border-box;
            &.video_control_box_small{
    
                .formation_select_box{
    
                    bottom: 7rpx;
                    .select_text{
    
                        font-size: 10.05rpx;
                    }
                    .select_menu{
    
                        bottom:0;
                        transform:scale(.8)                    
                    }
                }
            }
            .time_bar_box{
    
                width: 100%;
                height: 12.25rpx;
                display: flex;
                align-items: center;
                .time_btn{
    
                    image{
    
                        width: 11.93rpx;
                        height: 9.42rpx;
                        margin-right: 10.05rpx;
                    }
                }
                .time_bar{
    
                    flex: 1;
                    display: flex;
                    justify-content:space-between;
                    font-size: 9.74rpx;
                    color: #f3f3f3;
                }
            }
            .video_btn{
    
                width: 100%;
                display: flex;
                justify-content: flex-end;
                text-align: right;
                margin-top: 6.28rpx;
                image{
    
                    width: 10.99rpx;
                    height: 10.05rpx;
                    margin-right: 15.7rpx;
                }
            }
        }
        .video_control{
    
            height: 47.11rpx;
            bottom: 4.71rpx;
            image{
    
                width: 10.05rpx !important;
                height: 10.05rpx !important;
                margin-right: 15.7rpx;
            }
        }
        ::v-deep {
    
            .vjs-control-bar{
    
                width: calc(100% - 74.75rpx - 37.69rpx);
                left: 76.75rpx;
                bottom: 27.84rpx;
            }
        }
    }
    .back{
    
        position: absolute;
        z-index: 200;
        top: 0;
        left: 0;
        width: 100%;
        height: 58.59rpx;
        padding-left: 14.64rpx;
        font-size: 13.82rpx;
        display: flex;
        align-items: center;
        cursor: pointer;
        background: linear-gradient(180deg, #000000 0%, rgba(0, 0, 0, 0) 100%);
		image{
    
			width: 6.44rpx;
			height: 12.3rpx;
			margin-right: 20.1rpx;
		}
    }
    .formation_select_box{
    
        position: relative;
        border-radius: 3.77rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        &.normal_mode{
    
            right: 118rpx;
        }
        .select_text{
    
            font-family: 'AkrobatMedium';
            font-size: 11.31rpx;
            color: #fff;
            position: relative;
        }
        .select_menu {
    
            width: 43.66rpx;
            position: absolute;
            bottom: 18.04rpx;
            left: -13rpx;
            z-index: 999;
            padding: 13.82rpx 0 0;
            text-align: center;
            box-sizing: border-box;
            border-radius: 3.77rpx;
            background: #000000;
            color: #F3F3F3;
            .select_menu_item {
    
                position: relative;
                z-index: 2;
                margin-bottom: 12.56rpx;
                >span {
    
                    display: inline-block;
                    width: 100%;
                    height: 100%;
                    box-sizing: border-box;
                    font-size: 10.05rpx;
                     font-family: AkrobatRegular;
                    &.active{
    
                        color: #38CB89;
                    }
                }
            }
        }
        .ani {
    
            animation: ani 0.2s;
        }
        @keyframes ani {
    
            0% {
    
                transform: scaleY(0);
            }
            100% {
    
                transform: scaleY(1);
            }
        }
        .mask_box {
    
            width: 70vw;
            height: 100vh;
            position: fixed;
            left: 0;
            top: 60rpx;
            z-index: 99;
            background: transparent;
        }
    }
    .video_time{
    
        position: absolute;
        bottom: 49.94rpx;
        width: 100%;
        box-sizing: border-box;
        padding:0 15.7rpx;
        line-height: 14.13rpx;
        display: flex;
        justify-content:space-between;
        z-index: 104;
    }
    .video_control{
    
        position: absolute;
        left: 0;
        z-index: 5;
        bottom: 5.85rpx;
        width: 161.13rpx;
        height: 35.15rpx;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 19.04rpx;
        box-sizing: border-box;
        width: 100%;
        p{
    
            display:flex;
            align-items: center;
            image{
    
                width: 17.59rpx;
                height: 17.59rpx;
                margin-right: 15.23rpx;
                // opacity: .6;
            }
            .video_volume{
    
                position: relative;
                .video_volume_slider{
    
                    display: none;
                    position: absolute;
                    right: 30px;
                    top: -85px;
                    padding-top: 5px;
                    background-color: rgba(0, 0, 0, 0.36);
                    &.hover{
    
                        display: inline-block;
                    }
                }
            }
        }
    }
    .video_list{
    
        position: absolute;
        width: 100%;
        top: 0;
        right: 0;
        z-index: 201;
        background: rgba(29, 29, 29, 0.8);
        backdrop-filter: blur(50px);
        color: #fff;
        padding-top: 25.13rpx;
        padding-bottom: 6.28rpx;
        box-sizing: border-box;
        display: flex;
        // transition: all 200ms;
        .close_img{
    
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            right: 236.81rpx;
			width: 20.5rpx;
			height: 75rpx;
        }
        .video_item{
    
            width: 83.54rpx;
            flex-shrink: 0;
            display: flex;
            flex-direction: column;
            margin-left: 12.56rpx;
            box-sizing: border-box;
            display: flex;
            &.active{
    
                    .text_over{
    
                        font-family: SysFontM;
                        color: #38CB89;
                    }
            }
            .video_img{
    
                width: 100%;
                height: 47.11rpx;
                box-sizing: border-box;
                position: relative;
                image.snapshot{
    
                    border-radius: 3.77rpx;
                    width: 100%;
                    height: 100%;
                    
                }
                .total_time{
    
                    font-family: SysFontR;
                    height: 12.89rpx;
                    position: absolute;
                    left: 2.92rpx;
                    bottom: 2.92rpx;
                    padding: 0 5.85rpx;
                    font-size: 8.2rpx;
                    line-height: 12.89rpx;
                    color: rgb(255, 255, 255);
                    background: rgba(30, 30, 30, .6);
                }
            }
            .clip_info{
    
                width: 100%;
                box-sizing: border-box;
                font-size: 8.2rpx;
                color: rgba(255, 255, 255, .8);
                position: relative;
                padding: 4.71rpx 0;
                // .clip_label{
    
                //     font-size: 10.68rpx;
                //     color: rgba(255, 255, 255,1);
                //     line-height: 14.06rpx;
                //     margin-bottom: 7.54rpx;
                // 	display: flex;
                // 	align-items: center;
                // }
            }
        }
    }
    .video_list_item {
    
        display: flex;
        width: 100%;
        overflow-x: auto;
    }
    .video_shrink{
    
        position: fixed;
        top: 50%;
        transform: translateY(-50%);
        right: 0;
		width: 20.5rpx;
		height: 75rpx;
    }

    .video_list_time {
    
        font-family: AkrobatRegular;
        margin-top: 3px;
    }
}
</style>;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37215621/article/details/133695681

智能推荐

Vue.js简单实现Todolist综合案例 (一) 选择完成或未完成 双击修改文本内容_vue 双击修改li内容-程序员宅基地

文章浏览阅读2.8k次,点赞4次,收藏7次。**Todolist综合案例(一)Todolist Vue.js基本实现方法我们先明白todolist这个案例的基本实现方法循环遍历方法跟跟套用事件方法 比如 v-for v-if 这些常用的方法todolist案例实用各种项目 基本样式也不会太大变化 说白了就是在俄罗斯套娃我也是刚刚入门的新手首先我们先基本引入Vue.js的环境cnpm install -g @vue/cli然后在创建Vue的基本项目vue create myapp然后直接cd 进去项目myapp启动就行 c_vue 双击修改li内容

Git解决fatal: unable to connect to github.com_fatal: unable to connect to git.newcapec.cn: git.n-程序员宅基地

文章浏览阅读1.6w次,点赞11次,收藏10次。git clone git://github.com/lajos/iFrameExtractor.git错误信息:bower error status code of git: 128fatal: unable to connect to github.com:github.com[0: 你的IP]: errno=Operation timed out原因:需要用https才能读到数..._fatal: unable to connect to git.newcapec.cn: git.newcapec.cn[0: 192.168.0.19

全网最强HTTP+Fiddler抓包实战教程 干得不能再干 (超级全面图文)_http抓包-程序员宅基地

文章浏览阅读1.5w次,点赞48次,收藏187次。居然有人干了5年开发,居然抓包都不会!但是不要怕,不要哭,跟着我学一定有收获! 兴趣就是你最好的老师,有兴趣就一定要学下去 ,卷死他们!_http抓包

LabView与SQL Server的连接 【转】_labview与sqlserver-程序员宅基地

文章浏览阅读1.2k次。 摘要:本文介绍LabView与SQL Server的连接方法。关键字:LabView、SQL Server、连接。 正文:在用LABVIEW进行数据采集分析过程中,一般会用到数据库。在数据量很大的场合,可考虑使用SQL SERVER。下面就介绍LABVIEW与SQL SERVER的连接方法。连接思路:先在SQL SERVER建立自己的数据库,如MyDB。然后在操作系统建立一数据源(ODBC),此数据源的驱动选择SQL S_labview与sqlserver

python从入门到精通 pdf 完整超清版-Python从入门到精通PDF高清完整版免费下载|百度云盘...-程序员宅基地

文章浏览阅读1.9k次。提取码:xahb内容简介《Python从入门到精通》从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Python进行程序开发应该掌握的各方面技术。全书共分22章,包括初识Python、Python语言基础、运算符与表达式、流程控制语句、列表与元组、字典与集合、字符串、Python中使用正则表达式、函数、面向对象程序设计、模块、异常处理及程序调试、文件及目录操作、操作数据库、GU..._python网络编程从入门到精通 pdf

易语言连接Mysql_易语言链接mysql-程序员宅基地

文章浏览阅读8.9k次。最近在写游戏的辅助工具研究了下易语言,下面就说下如何连接Mysql。.版本 2.支持库 mysql.支持库 specMysql句柄 = 连接MySql (“127.0.0.1”, “root”, “root123”, “test”, 3306)查询部门语句 = “select * from department”执行SQL语句 (Mysql句柄, 查询部门语句)记录集..._易语言链接mysql

随便推点

Visual Studio 2012,运行后窗口闪退解决方法大全_visual2012闪退-程序员宅基地

文章浏览阅读2.2k次。相信各位都有一种想要打人的节奏,每次编写代码,在代码编写好了之后,运行编译代码却出现窗口闪退的结果,下面,我将介绍几种解决Visual Studio 2012运行后窗口闪退方法。希望可以帮助大家解决这个问题。 方法一:运行程序时按 Ctrl +F5 ,然后运行程序。 此方法只是解决一般的闪退,菜鸟级的新手如果出现闪退,不_visual2012闪退

【笔记】行测——常识判断之地理常识总结与归纳(二)_重庆四川行测笔记汇总-程序员宅基地

文章浏览阅读759次。第二章 世界地理一、海陆概况(一)七大洲(二)七大洲大小(三)大洲分界线(四)四大洋(五)海峡和运河二、山川湖泊(一)高原、平原、山脉(二)河流、城市与文明(三)世界之最第三章 中国地理一、中国地理概况1.位置半球维度海陆2.疆域面积四至临海3.邻国二、山形地貌(一)四大高原(二)四大盆地(三)三大平原(四)三大丘陵(五)名山大川1.五岳2.三山(六)宗教名山1.四大佛教名山2.四大道教名山(七)著名地貌1.喀斯特地貌2.丹霞地貌3.雅_重庆四川行测笔记汇总

Unity-URP RenderFeature CommandBuffer.DrawMesh始终是蓝色的?_unity urp偏蓝-程序员宅基地

文章浏览阅读186次。URP CommandBuffer.DrawMesh 渲染不正确的?_unity urp偏蓝

虚幻4中的程序化生成【1】程序化生成河流。_虚幻4河流demo-程序员宅基地

文章浏览阅读7.5k次,点赞7次,收藏34次。给自己立了很多flag,由于时间原因很多系列都还在写,算是循序渐进的总结。在程序化生成系列里,将会有如下记述:【1】程序化生成河流主要内容有@1 shader的自动调整(如河流的深浅,河水的波涛程度) @2 河流形状的调整,我们只需要编辑一条样条线,河流根据这条样条线自适应形状。【2】程序化生成森林主要内容有:@1用随机种子随机生成森林。减少美_虚幻4河流demo

Windows系统目录及常用快捷键_目录后的............快捷键-程序员宅基地

文章浏览阅读6.2k次。1.系统目录用户目录存放用户登录后的配置文件Windows目录为系统安装目录 system32存放系统配置文件 config目录内的SAM文件存放用户的账户和密码,备份后删除该文件登录用户无需密码(需要使用第三方PE才能操作该文件) drives目录下 etc目录内的hosts文件存放用于解析域名的地址 program file(x86):64位操作系统才有的目录。32位应用程序安装于该目录 program file:应用程_目录后的............快捷键

simplexml_load_string-程序员宅基地

文章浏览阅读590次。2019独角兽企业重金招聘Python工程师标准>>> ...

推荐文章

热门文章

相关标签