Yii2 插件系列——kartik\detail\DetailView

前言

前段时间研究了DetailView插件结合自定义字段的显示与编辑,DetailView插件本身没有这么灵活,要实现这种效果必须得改造插件。显示与编辑DetailView插件都有了,只需要我们把自定义的字段加进去就行可以实现了。但是怎么加进去呢?既然是自定义字段,那肯定是可有可无,不能写死的,我来分享下具体实现思路吧!

效果图

提交时间、昵称、联系人分类、性别属于自定义字段

Yii2 插件系列——kartik\detail\DetailView_第1张图片

找插件源码

找插件的源码(vendor\kartik-v\yii2-detail-view\DetailView.php),可以通过它方法的命名或者打印测试找到相关的代码,知点击详细时走插件的如下方法:

 /**
     * Renders the main detail view widget
     *
     * @return string the detail view content
     */
    protected function renderDetailView()
    {  
        $rows = [];
        foreach ($this->attributes as $attribute) {
            $rows[] = $this->renderAttributeRow($attribute);
        }
        $tag = ArrayHelper::remove($this->options, 'tag', 'table');
        $output = Html::tag($tag, implode("\n", $rows), $this->options);
        return ($this->bootstrap && $this->responsive) ?
            '
' . $output . '
' : '
' . $output . '
'; }

重写类及其方法

1、类与方法都找到了,就重写。把DetailView类以及renderDetailView方法里涉及的方法、组件都拷贝过来重写一遍,并继承父类\kartik\detail\DetailView。

2、仿造父类的public $attributes;属性给子类增加public $custom;属性,原因是$attributes属性的字段与自定义字段走的不是同一个model,所以必须得定义一个新的属性来用。

3、重写完了之后代码如下(重点注意的部分我在代码中已加上注释):

 'hiddenInput',
        self::INPUT_TEXT => 'textInput',
        self::INPUT_PASSWORD => 'passwordInput',
        self::INPUT_TEXTAREA => 'textArea',
        self::INPUT_CHECKBOX => 'checkbox',
        self::INPUT_RADIO => 'radio',
        self::INPUT_LIST_BOX => 'listBox',
        self::INPUT_DROPDOWN_LIST => 'dropDownList',
        self::INPUT_CHECKBOX_LIST => 'checkboxList',
        self::INPUT_RADIO_LIST => 'radioList',
        self::INPUT_HTML5_INPUT => 'input',
        self::INPUT_FILE => 'fileInput',
        self::INPUT_WIDGET => 'widget',
    ];

    // dropdown inputs
    private static $_dropDownInputs = [
        self::INPUT_LIST_BOX => 'listBox',
        self::INPUT_DROPDOWN_LIST => 'dropDownList',
        self::INPUT_CHECKBOX_LIST => 'checkboxList',
        self::INPUT_RADIO_LIST => 'radioList',
    ];
    protected function renderDetailView()
    { 
        $rows = [];
        foreach ($this->attributes as $attribute) {
            $rows[] = $this->renderAttributeRow($attribute);
        }
        //注意点一:增加循环获取自定义字段的值
        foreach ($this->custom['attributes'] as $attribute) {
            $rows[] = $this->renderCustomAttributeRow($attribute);
        }
        $tag = ArrayHelper::remove($this->options, 'tag', 'table');
        $output = Html::tag($tag, implode("\n", $rows), $this->options);
        return ($this->bootstrap && $this->responsive) ?
            '
' . $output . '
' : '
' . $output . '
'; } //自定义字段的显示 protected function renderCustomAttributeRow($attribute) { //注意点二:只留这三行代码,把其它多余的删除 $this->_rowOptions = ArrayHelper::getValue($attribute, 'rowOptions', $this->rowOptions); $content = $this->renderCustomAttributeItem($attribute); return Html::tag('tr', $content, $this->_rowOptions); } protected function renderCustomAttributeItem($attribute) { $labelColOpts = ArrayHelper::getValue($attribute, 'labelColOptions', $this->labelColOptions); $valueColOpts = ArrayHelper::getValue($attribute, 'valueColOptions', $this->valueColOptions); if (ArrayHelper::getValue($attribute, 'group', false)) { $groupOptions = ArrayHelper::getValue($attribute, 'groupOptions', []); $label = ArrayHelper::getValue($attribute, 'label', ''); if (empty($groupOptions['colspan'])) { $groupOptions['colspan'] = 2; } return Html::tag('th', $label, $groupOptions); } if ($this->hideIfEmpty === true && empty($attribute['value'])) { Html::addCssClass($this->_rowOptions, 'kv-view-hidden'); } if (ArrayHelper::getValue($attribute, 'type', 'text') === self::INPUT_HIDDEN) { Html::addCssClass($this->_rowOptions, 'kv-edit-hidden'); } $value = $attribute['value']; if ($this->notSetIfEmpty && ($value === '' || $value === null)) { $value = null; } $dispAttr = $this->formatter->format($value, $attribute['format']); Html::addCssClass($this->viewAttributeContainer, 'kv-attribute'); Html::addCssClass($this->editAttributeContainer, 'kv-form-attribute'); $output = Html::tag('div', $dispAttr, $this->viewAttributeContainer) . "\n"; //var_dump($this->editAttributeContainer);exit; if ($this->enableEditMode) { $editInput = ArrayHelper::getValue($attribute, 'displayOnly', false) ? $dispAttr : $this->renderFormCustomAttribute($attribute); $output .= Html::tag('div', $editInput, $this->editAttributeContainer); } return Html::tag('th', $attribute['label'], $labelColOpts) . "\n" . Html::tag('td', $output, $valueColOpts); } protected function renderFormCustomAttribute($config) { if (empty($config['attribute'])) { return ''; } //注意点三:把这里的model注释掉,不能用,这是attribute的model //$model = ArrayHelper::getValue($config, 'editModel', $this->model); //if (!$model instanceof Model) { $model = $this->model; //} $attr = ArrayHelper::getValue($config, 'updateAttr', $config['attribute']); $input = ArrayHelper::getValue($config, 'type', self::INPUT_TEXT); $fieldConfig = ArrayHelper::getValue($config, 'fieldConfig', []); $inputWidth = ArrayHelper::getValue($config, 'inputWidth', ''); $container = ArrayHelper::getValue($config, 'inputContainer', []); if ($inputWidth != '') { Html::addCssStyle($container, "width: {$inputWidth}"); // deprecated since v1.7.4 } $template = ArrayHelper::getValue($fieldConfig, 'template', "{input}\n{error}\n{hint}"); $row = Html::tag('div', $template, $container); if (static::hasGridCol($container)) { $row = '
' . $row . '
'; } $fieldConfig['template'] = $row; if (substr($input, 0, 8) == "\\kartik\\") { Config::validateInputWidget($input, 'as an input widget for DetailView edit mode'); } elseif ($input !== self::INPUT_WIDGET && !in_array($input, self::$_inputsList)) { throw new InvalidConfigException( "Invalid input type '{$input}' defined for the attribute '" . $config['attribute'] . "'." ); } $options = ArrayHelper::getValue($config, 'options', []); $widgetOptions = ArrayHelper::getValue($config, 'widgetOptions', []); $class = ArrayHelper::remove($widgetOptions, 'class', ''); if (!empty($config['options'])) { $widgetOptions['options'] = $config['options']; } //return array("options"=> array("class"=> "form-group")); //return "yyyy"; if (Config::isInputWidget($input)) { $class = $input; return $this->_form->field($model, $attr, $fieldConfig)->widget($class, $widgetOptions); } if ($input === self::INPUT_WIDGET) { if ($class == '') { throw new InvalidConfigException("Widget class not defined in 'widgetOptions' for {$input}'."); } return $this->_form->field($model, $attr, $fieldConfig)->widget($class, $widgetOptions); } if (in_array($input, self::$_dropDownInputs)) { $items = ArrayHelper::getValue($config, 'items', []); return $this->_form->field($model, $attr, $fieldConfig)->$input($items, $options); } if ($input == self::INPUT_HTML5_INPUT) { $inputType = ArrayHelper::getValue($config, 'inputType', self::INPUT_TEXT); return $this->_form->field($model, $attr, $fieldConfig)->$input($inputType, $options); } /* 注意点四:把原来的返回值改写。至于为什么要改写成如下,原因有: 1、用$this->_form->field()的话会走attribute的model,改写失败; 2、可以参照$this->_form->field()的用法,然后查看原码生成功div、input的规律你就明白为什么要这么改写了。 */ $name = $this->custom['id']."[".$config['attribute']."]"; $id = strtolower($this->custom['id'])."-".$config['attribute']; $html = Html::input('text', $name, $config['value'], ['class' => "form-control",'id'=> $id]); $html .= Html::tag('div', "", ['class' => 'help-block']); $html = Html::tag('div', $html, []); $fieldclass = "field-".$id; $html = Html::tag('div', $html, ['class' => $fieldclass]); return $html; } }

视图用custom属性

    'contact-view',
        
        'formOptions'=>[
            'id'=>'contact-form-view',
            'action'=>'/contact/update?id='.$model->id."&salesId=".$model->sale_id,
            'options'=>['data-form'=>'public-form-submit'],
         ],
        'model' => $model,
        'condensed'=>false,
        'hover'=>true,
        'mode'=>Yii::$app->request->get('edit')=='t' ? DetailView::MODE_EDIT : DetailView::MODE_VIEW,
        'panel'=>[
           'heading'=>$this->title,
           'type'=>DetailView::TYPE_INFO,
        ],
        'custom' => $custom, //custom属性放这
        'attributes' => $attributes,
        'deleteOptions'=>[
            'class'=>"prohibit deletet",
            'label'=>'',
        ],
        'enableEditMode'=>true,
        'fadeDelay'=>0, //关闭动画
    ]) ?>

$custom的数组格式如下:

Array
(
    [id] => ClassForm
    [attributes] => Array
        (
            [0] => Array
                (
                    [attribute] => add_time
                    [value] => 
                    [label] => 提交时间
                    [format] => text
                )

            [1] => Array
                (
                    [attribute] => nickname
                    [value] => 测试姓名
                    [label] => 昵称
                    [format] => text
                )

            [2] => Array
                (
                    [attribute] => sort
                    [value] => 
                    [label] => 联系人分类
                    [format] => text
                )

            [3] => Array
                (
                    [attribute] => sex
                    [value] => 男
                    [label] => 性别
                    [format] => text
                )

        )

)

注意:如果编辑与保存刷新的页面分开写,那么记得也要在刷新的页面加上custom属性,不然保存刷新后加上的自定义字段就消失了。

总结分析

以上就是我要给大家分享的DetailView插件结合自定义字段的显示与编辑的实现过程。
搞程序,水很深,不常总结,将来更费劲。
(完)

相关资料

1、DetailView

你可能感兴趣的:(yii2,php,javascript,html5,node.js)